JPA交易如何运作

时间:2012-06-27 07:09:49

标签: hibernate jpa transactions jpa-2.0

每当我想要持久保存任何实体时,都会执行以下代码。事情似乎工作正常,但我不明白它是如何运作的!

EntityManager em = getEntityManager();
EntityTransaction userTransaction = em.getTransaction();
userTransaction.begin();
em.persist( ent );
userTransaction.commit();

上面的EntityManager是整个应用程序共享的单个实例。开始交易后;我只是说em.persist(实体).. hibernate如何知道它属于哪个事务!

假设我的应用程序上有10个并发用户,并且所有10个线程都在代码上执行。因此,创建并提交了10个独立事务。但所有10个不同的实体我并没有将它们与各自的交易联系起来;那么JPA如何能够解决这个问题呢!

根据答案;我们在下面;我们是说每个线程应该有一个EntityManager实例吗?这不会是服务器上的杀戮!我们应该汇集这些实例吗?它不等于再次实现连接池吗?

4 个答案:

答案 0 :(得分:6)

它正在使用ThreadLocal变量进行交易。

另请参阅UserTransaction的文档:

  

开始()
  创建一个新事务并将其与当前线程关联。

您不应该共享EntityManager,因为它不能保证是线程安全的。

但是,如果您在EJB中注入它,则不必担心线程安全:http://www.adam-bien.com/roller/abien/entry/is_in_an_ejb_injected

如果您使用Spring注入它,您将获得一个线程安全的代理:http://static.springsource.org/spring/docs/3.1.1.RELEASE/spring-framework-reference/html/orm.html#orm-jpa-straight

  

虽然EntityManagerFactory实例是线程安全的,但EntityManager实例却不是。注入的JPA EntityManager的行为类似于从应用程序服务器的JNDI环境获取的EntityManager,如JPA规范所定义。它将所有调用委托给当前的事务性EntityManager,如果有的话;否则,它会回退到每个操作新创建的EntityManager,实际上使其使用线程安全。

答案 1 :(得分:5)

这很有效,因为你很幸运。幸运的是,意味着以正确的顺序调用commit和begin。

您确实使用来自多个线程的单个实体管理器实例。这是不对的,因为它不能保证是线程安全的。通过EntityTransaction访问资源级别事务绑定到实体管理器实例,而不是线程。

因此,结果是您正在共享相同的EntityTransaction并幸运地连续使用它进行多次交易。使用它来串行和结束多个事务很好,但是从许多线程中使用它不是。

在hibernate(4.1.4)中,引用存储在AbstractEntityManageImpl类的tx实例字段中,但这只是实现细节。

答案 2 :(得分:1)

事务使用ThreadLocal变量以某种方式与当前线程相关联。

答案 3 :(得分:0)

我建议您了解JTA无论Hibernate如何都能正常工作 - 这对您的理解非常重要 另外,阅读有关容器管理的事务和bean管理的事务。
如果您正在使用容器管理的事务,则可以为正在注入EntityManager的bean指定事务范围 - 例如 - 如果范围是REQUIRED,则意味着如果另一个bean调用此bean,而不是在事务的上下文中,则将打开一个新事务。如果事务已存在,那么您将使用相同的事务。了解这一点非常重要,因为事务是系统中的一种昂贵资源。

事务对象与ThreadLocal相关联,但是,另一个线程可能会恢复暂停的事务,这取决于您的TransactionManager的实现(我在谈论JBossTransactionManager