一尘不染

Jersey,Guice和Hibernate-EntityManager线程安全

hibernate

我已经在我的应用程序中以相同的方式使用了本教程:http : //www.benmccann.com/hibernate-with-jpa-annotations-
and-guice/

我的应用程序是JAX-RS Web服务,它将接收许多并发请求并进行数据库更新。

GenericDAOImpl.java实现:

public class GenericDAOImpl<T> implements GenericDAO<T> {

    @Inject
    protected EntityManager entityManager;

    private Class<T> type;

    public GenericDAOImpl(){}

    public GenericDAOImpl(Class<T> type) {
        this.type = type;
    }

    @Override
    public void save(T entity) {
        entityManager.getTransaction().begin();
        entityManager.persist(entity);
        entityManager.getTransaction().commit();
    }

}

如果2个并发线程尝试保存实体,我得到

java.lang.IllegalStateException: Transaction already active

如果我评论交易,保存效果很好。

我尝试使用

@Inject
protected Provider<EntityManager> entityManagerProvider;

要么

@Inject
protected EntityManagerFactory entityManagerProvider;

并针对每个请求:

EntityManager entityManager = entityManagerProvider.get()

但是然后我得到:

org.hibernate.PersistentObjectException: detached entity passed to persist

什么是实现Guice + Hibernate EntityManager注入/线程安全的通用DAO类的正确方法?

更新

来自http://www.benmccann.com/hibernate-with-jpa-annotations-and-
guice/的
Andrew Rayner评论

“逻辑还不是真正可以投入生产的-至少在Web应用程序中使用了。

Hibernates连接池是非常基本的,并且尚未准备就绪,建议使用数据源池,例如c3p0。

EntityManager不应被重用-它应按事务/请求创建。很可能污染后续请求。

如果出现问题,也不会进行事务回滚。

一种有趣的方法–但是对于Web应用来说,使用Guices自己的Persist扩展模块来管理EntityMananger实例和事务的生命周期会更加安全。”


阅读 180

收藏
2020-06-20

共1个答案

一尘不染

问题是我的端点被@Singleton注释,因此它在并发调用期间重用了相同的EntityManager。删除@Singleton之后,在并发调用期间,将使用不同的EntityManager对象。如果端点调用是后续的,则可能是将使用先前的/旧的EntityManager。

高度简化的示例:

@Path("/v1/items")
public class ItemsService {

    @Inject
    private EntityManager entityManager;

    @POST
    @Path("/{id}")
    @Consumes(MediaType.APPLICATION_JSON)
    @Produces(MediaType.APPLICATION_JSON)
    public void saveItem(){
         entityManager.getTransaction().begin();
         entityManager.persist(new Item());
         entityManager.getTransaction().commit();
    }
}
2020-06-20