Jersey,Guice和Hibernate - EntityManager线程安全 [英] Jersey, Guice and Hibernate - EntityManager thread safety

查看:125
本文介绍了Jersey,Guice和Hibernate - EntityManager线程安全的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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



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

GenericDAOImpl.java实现:

  public class GenericDAOImpl< T>实现GenericDAO< T> {

@Inject
受保护的EntityManager entityManager;

私人课程< T>类型;

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:事务已经激活

code>

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



我试过使用

  @Inject 
protected Provider< EntityManager> entityManagerProvider;

  @Inject 
protected EntityManagerFactory entityManagerProvider;

以及每个请求:

<$ p $但是后来我得到了以下结果:

EntityManager entityManager = entityManagerProvider.get()

  org.hibernate.PersistentObjectException:传递给persist的分离实体

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

更新



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


这个逻辑不是真正的生产准备 - 至少如果用在web应用程序中的话。

Hibernates连接池是非常基本的,不是生产就绪 - 建议使用诸如c3p0之类的数据源池。



EntityManager不应该被重用 - it i这意味着每个事务/请求都会被创建。有一个污染后续请求的好机会。



如果出现问题,也没有事务回滚。



一个有趣的方法 - 但是webapps使用Guices自己的Persist扩展模块来管理EntityMananger实例和事务的生命周期会更安全。 / div>

问题是我的端点被注释为@Singleton,所以它在并发调用期间重用了同一个EntityManager,在并发调用期间删除了@Singleton后,使用了不同的EntityManager对象,如果端点调用是后续的,



高度简化的示例:

 <$ c 
$ public $ Items $ {
$ b @Inject
private EntityManager entityManager;

@POST
@Path(/ {id})
@Consumes(MediaType.APPLICATION_JSON)
@Product ces(MediaType.APPLICATION_JSON)
public void saveItem(){
entityManager.getTransaction()。begin();
entityManager.persist(new Item());
entityManager.getTransaction()。commit();
}
}


I have used this tutorial them same way in my application: http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/

My app is JAX-RS web service which will receive many concurrent requests and make updates to database.

GenericDAOImpl.java implementation:

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();
    }

}

If 2 concurrent threads try to save entity, I get

java.lang.IllegalStateException: Transaction already active

Saving works well if I comment transaction.

I have tried to use

@Inject
protected Provider<EntityManager> entityManagerProvider;

or

@Inject
protected EntityManagerFactory entityManagerProvider;

and for each request:

EntityManager entityManager = entityManagerProvider.get()

But then I get:

org.hibernate.PersistentObjectException: detached entity passed to persist

What is correct way to implement Guice + Hibernate EntityManager injection / thread-safe generic DAO class?

UPDATE

Andrew Rayner comment from http://www.benmccann.com/hibernate-with-jpa-annotations-and-guice/

"The logic isn’t really production ready – at least if used in a web app.

Hibernates connection pool is very basic and is not production ready – the recommendation is to use a datasource pool such as c3p0.

EntityManager shouldn’t be reused – it is intended to be created per transaction/request. There is a good chance of polluting subsequent requests.

There is also no transaction rollback if something goes wrong.

An interesting approach – but it would be much safer for webapps to use Guices own Persist extension module for managing the lifecycle of EntityMananger instances and transactions."

解决方案

The problem was that my endpoint was annotated with @Singleton so it reused the same EntityManager during concurrent calls. After removing @Singleton, during concurrent calls, different EntityManager objects are used. If endpoint calls are subsequent, it may be that previous/old EntityManager will be used.

Highly simplified example:

@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();
    }
}

这篇关于Jersey,Guice和Hibernate - EntityManager线程安全的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆