容器管理的事务 之 容器管理的持久化上下文

JPA支持两种事务类型

本地资源事务(RESOURCE_LOCAL):使用JDBC驱动管理的本地事务。

Java事务API(JTA):可用于管理分布式事务,管理多数据源的情况。

容器管理的EntityManager总是使用JTA事务。应用程序管理的EntityManager可以使用本地资源事务,也可以使用JTA事务。

在JavaSE环境下,默认的事务类型是RESOURCE_LOCAL,而在JavaEE环境下,默认的事务类型是JTA。

事务类型在persistence.xml中定义。

         只能有一个持久化上下文与JTA关联,并且只能有一个持久化上下文在事务中传播

         对于容器管理的EntityManager,在同一事务中必须使用相同的持久化上下文。

          事务范围内的持久化上下文:事务范围内的持久化上下文将其生命周期绑定到某个事务,在需要的时候,事务范围内的持久化上下文由事务范围内的EntityManager负责创建,之所以说“在需要的时候”,是因为事务范围内的持久化上下文是“懒加载”的,只有在EntityManager实例调用相关的数据访问方法并且当前不存在可用的持久化上下文的时候,才会创建持久化上下文。

          扩展的持久化上下文:扩展的持久化上下文与有状态会话Bean绑定。不同于事务范围内的持久化上下文为每一个事务创建一个新的持久化上下文,有状态会话Bean中扩展的EntityManager总是使用相同的持久化上下文。有状态会话Bean总是只和一个持久化上下文绑定,并且在有状态会话Bean创建时创建该持久化上下文,在有状态会话Bean销毁时注销该持久化上下文。也就是说,不同于事务范围内的持久化上下文,扩展的持久化上下文不是“懒加载”的。

          持久化上下文的冲突:当调用某个方法时有若干个持久化上下文,则会出现持久化上下文冲突,抛出异常。有个特殊情况,即在一个有状态会话Bean的扩展持久化上下文中调用另一个有状态会话Bean的方法,并且被调用的会话Bean也使用扩展持久化上下文,这样当调用被调用的会话Bean中方法时虽有两个持久化上下文可用,但并不会出现冲突。被调用的会话Bean继承调用者的持久化上下文。

 

容器管理的事务 应用程序管理的持久化上下文

 

          应用程序管理的持久化上下文与容器管理的持久化上下文的一个最大的区别是:只能有一个容器管理的持久化上下文与事务关联,但是可以有任意多个应用程序管理的持久化上下文与当前事务关联

应用程序管理的持久化上下文有两种方式加入JTA事务:

如果持久化上下文是在事务内部创建的,则持久化提供者自动将该持久化上下文关联到当前事务;

 

如果持久化上下文不是在本事务内部创建的(比如在另一个已经结束的事务中创建的),则需要调用EntityManager.joinTransaction()方法手动将持久化上下文与事务绑定。

          由于应用程序管理的EntityManager不会自动传播,唯一与其他组件共享受管实例的方法是共享EntityManager实例。并且在不同的事务当中使用EntityManager时必须先要调用joinTransaction()方法。

           对于应用程序管理的EntityManager而言,可以在事务结束前关闭EntityManager,这样EntityManager实例就无法使用了,但是之前做的操作在事务结束时仍然会同步到数据库。因为持久化上下文会存活到事务结束。

           由于在同一个JTA事务当中可以存在多个持久化上下文,所以当事务提交时,可能若干持久化上下文同时执行flush操作,这样会存在隐性问题,比如,如果一个实例存在于多个持久化上下文中,flush的结果会如何?结果是无法预料的。因此应该避免在同一事务中将一个实例加入多个持久化上下文。

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐