DAO 中的 ThreadLocal JPA EntityManager

发布于 2024-12-04 16:50:50 字数 677 浏览 0 评论 0 原文

在我的 DAO 类中,我引用了 EntityManager。我想通过使用 ThreadLocal 使对 EntityManager 的访问成为线程安全的。

到目前为止,我的尝试仅导致了 NullPointerException,而且我似乎找不到合适的示例。

有人可以给我举个例子或者指出我正确的方向吗?

更新:我已经尝试过BalusC的建议,但是当我同时通过JSF和JAX-RS Web服务访问DAO时,我仍然收到错误:

 org.hibernate.exception.GenericJDBCException: could not load an entity
 java.sql.SQLException: You can't operate on a closed Connection!!!
 java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement

我正在使用C3P0,所以我不知道为什么关闭连接会出现问题。

update2:BalusC 的最后一条评论似乎解决了我的问题:至少,您不应该在整个应用程序中共享 DAO 类的单个实例。根据每个请求创建一个新的。

In my DAO classes I have a reference to an EntityManager. I want to make the acces to the EntityManager thread-safe by using ThreadLocal.

So far my attempts have only resulted in NullPointerExceptions, and I can't seem to find a decent example.

Can someone provide me with an example or point me in the right direction?

update: I've tried BalusC's suggestion, but when I acces the DAO through JSF and the JAX-RS webservice at the same time, I'm still getting errors:

 org.hibernate.exception.GenericJDBCException: could not load an entity
 java.sql.SQLException: You can't operate on a closed Connection!!!
 java.lang.NullPointerException
    at com.mchange.v2.c3p0.impl.NewProxyConnection.prepareStatement

I'm using C3P0, so I don't know why a closed connection is a problem.

update2: BalusC's last comment seemed to have solved my problem: At least, you should not have a single instance of the DAO class shared throughout the application. Create a new one on every request.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

樱桃奶球 2024-12-11 16:50:50

我想通过使用 ThreadLocal 使对 EntityManager 的访问成为线程安全的。

不要这样做。让容器来操心这个事情吧。我会让你的 DAO 成为 @Stateless EJB 并使用 @PersistenceContext 注入 EntityManager。例如,

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public User find(Long id) {
        return em.find(User.class, id);
    }

    // ...
}

要将其注入 JSF 托管 bean 或 JAX-RS 服务中,只需使用 @EJB

@EJB
private UserService userService;

要控制事务级别,请使用@TransactionAttribute 注释(默认为 TransactionAttributeType#REQUIRED)。

I want to make the acces to the EntityManager thread-safe by using ThreadLocal.

Don't do that. Let the container worry about this. I'd make your DAOs a @Stateless EJB and use @PersistenceContext to inject the EntityManager. E.g.

@Stateless
public class UserService {

    @PersistenceContext
    private EntityManager em;

    public User find(Long id) {
        return em.find(User.class, id);
    }

    // ...
}

To inject it in your JSF managed beans or JAX-RS services, just use @EJB:

@EJB
private UserService userService;

To control the transaction level, use @TransactionAttribute annotation (which defaults to TransactionAttributeType#REQUIRED).

把时间冻结 2024-12-11 16:50:50

当您不在 EJB 应用程序服务器中时,为什么要尝试 CDI 注入 EntityManger?只需使用 javax.persistence.Persistence 和持久性单元的名称来获取 EntityManagerFactory,然后使用 EMF 来获取 EntityManager,就像在servlet 中一样。使用数据库事务锁来确保对数据库的一致并行访问,不要在java代码中使EntityManager“线程”安全。

Why are you tring to CDI inject your EntityManger when you're not in an EJB app server? Just Grab a hold of your EntityManagerFactory using javax.persistence.Persistence and the name of your persistence unit, then with the EMF get a hold of your EntityManager(s) like in a servelet and what not. Use data base transaction locks to ensure consistem parallel access to the db, don't go around making EntityManager "thread" safe in java code.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文