让我们专注于RequiresNew Attribute
。
以下是链接
的修改图
因此,请说method-B
注明RequiredNew attribute
。
所以根据理论,当method-A
调用method-B
时,将启动一个新事务,并且已经启动的事务将被暂停,当method-B
返回时,将提交新事务。< / p>
现在考虑在S1
部分,我们使用entitymanager.persist()
创建一个jpa实体,现在我们将此实体传递给method-B
,它设置实体的name
字段。 / p>
现在当我们从method-B
返回时,如果commit
事务如同在db中一样,那么实体未被method-A
启动的暂停事务提交?
PS:Db以读取提交的隔离级别运行。
答案 0 :(得分:5)
此方案中的情况受以下因素控制:
使用@PersistenceContext
注释创建实体管理器会导致创建一个Transaction-Scoped实体管理器以及persistence.xml
文件定义的关联持久性上下文。上下文将跟踪persistence.xml
中指定类型的实体。在持久化,找到(em.find()
)或合并后,实体将在该上下文中进行管理。上下文将与当前运行的JTA事务关联。当此事务结束时,持久化上下文中存在的更改可以刷新并提交 - 或者在事务本身回滚时回滚。
在示例场景中,假设使用Bean2的本地接口。调用Bean2-MethodB
时,由于该方法使用@TransactionAttribute(TransactionAttributeType.REQUIRES_NEW)
注释,因此启动了新事务。调用方法的事务被暂停。没有持久性上下文与新创建的事务关联。但是,传入的实体将引用由Bean1-MethodA
处理的实体的相同实例,并且此实例是Bean1的实体管理器的持久性上下文中的管理实体。因此,即使暂停与此持久性上下文关联的事务,也不会在另一个事务中修改该实体。
因此,名义的事件序列是;
Bean1-MethodA
,TransactionA启动。Bean1-MethodA
调用Bean2MethodB
并将'entity'作为参数传递。Bean2-MethodB
修改字段entity.name
。Bean2-MethodB
中的实体更改对Bean1-MethodA
和持久性上下文可见Bean1-MethodA
完成,TransactionA提交和持久化上下文更改被刷新/提交到DB Bean2-MethodB
当Bean2-MehodB的交易回滚时会发生什么?
值得注意的是,如果在Bean2-MethodB
和Bean2-MethodB’s
事务回滚中进行实体字段更改,则不会还原对类字段的更改。任何JTA资源都将回滚,但实体字段更改仍会反映在数据库中Bean1-MehodA
成功完成,从而导致潜在的不一致。也许真实世界的问题可能会迫使这样的解决方案,但可能更好地修改事务中可以回滚这些更改的实体。
上述方案在eclipse-mars / WildFly8.2 / HibernateJPA / Derby
上进行了测试使用远程EJB调用
此处,实体参数被序列化,从而在Bean2-MethodB
中生成实体的副本。此副本与Bean1-MethodA
中使用的副本不同,它是一个分离的实体,不与Bean1-MethodA
共享。 (这有时称为按值传递,请参阅本答案末尾的注释)。为了使更改能够反映在Bean1-MethodA’s
持久性上下文中,需要将实体返回到Bean1-MethodA
,然后使用实体管理器将其合并到持久性上下文中。无论远程ejb调用是否在事务中进行,都需要进行此合并。
关于“传递参考”和“传递价值”的说明。
根据定义,java中的所有参数都按值传递。有关堆栈溢出的良好扩展讨论,请参阅Is Java "pass-by-reference" or "pass-by-value"?。这里重要的是,对于本地接口,Java将引用的副本 - 指针 - 传递给共享实例 - 这是人们通常理解的“传递引用”。远程接口在远程端创建实体实例的副本,因此调用方法无法看到对此副本的任何更改。这有时被称为按值传递。