考虑一下我正在使用的一些代码的简化 View :
@Stateless(...)
@Remote(...)
@TransactionAttribute(TransactionAttributeType.MANDATORY)
public class FirstEjbType {
@EJB(...)
private SecondEjbType secondEjb;
@EJB(...)
private ThirdEjbType thirdEjb;
public void doSomething() {
secondEjb.doSomething(); // WRITES SOMETHING TO THE DATABASE
thirdEjb.doSomething(); // CAN'T SEE THAT SOMETHING IN THE DATABASE!
}
我已经设置了 TransactionAttribute
对 MANDATORY
的注释在类(class)。我理解这意味着所有方法,如 doSomething()
必须在提供的事务中调用。在这种情况下,我们使用容器管理的事务。
TransactionAttribute
在 SecondEjbType
中根本没有使用或 ThirdEjbType
...既不在类也不在方法级别。我理解这意味着 secondEjb.doSomething()
和 thirdEjb.doSomething()
都将在为 firstEjb.doSomething()
提供的交易中运作.
但是,我严重错过了一些东西!如代码注释所示... secondEjb
将数据写入数据库,thirdEjb
读取该数据作为其操作的一部分。由于所有这些都在同一个事务中运行,我不认为隔离级别会有任何问题。 但是,无论出于何种原因,secondEjb
数据库写入对 thirdEjb
不可见.
我一直跟踪到最大值,显然没有异常、错误或回滚问题……最初的写入对后续读取来说是不可见的。我并没有自称是世界上最伟大的交易管理大师……我是否遗漏了一些明显的东西,或者我的概念理解是否基本正确,问题可能出在其他地方?
更新 - 以下是 johnstok 要求的其他信息:
- 我在 GlassFish 中运行
- 我不确定您所说的“非标准刷新模式”是什么意思,所以我认为答案是否定的。
- 我的 persistence.xml 文件如下所示:
<persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0">
<persistence-unit name="pu" transaction-type="JTA">
<jta-data-source>jdbc/datasource</jta-data-source>
<exclude-unlisted-classes>false</exclude-unlisted-classes>
<properties>
<property name="toplink.cache.shared.default" value="false"/>
</properties>
</persistence-unit>
</persistence>
最佳答案
首先要检查的是 bean 2 和 3 使用 @PersistenceContext EntityManager
来获取 EntityManager 而不是 @PersistenceUnit EntityManagerFactory
后跟一个createEntityManager()
调用。
其次,检查 DataSource
是否实际设置为参与 JTA 事务(autoCommit 或相关属性应该关闭)。
最后,检查传播的一种快速但粗略的方法是调用 EntityManager.getDelegate()
方法并检查生成的对象在整个预期事务中是否相同范围。
下面是幕后工作原理.... EntityManager
在创建 bean 时注入(inject)到它是一个假的,一个简单的外观。当您尝试在事务中使用 EntityManager 引用时,容器实际上会在当前事务中挖掘,找到隐藏在事务范围内的真实 EntityManager 并将您的调用委托(delegate)给那个 EntityManager(如果事务中没有 EntityManager,容器将创建一个并添加它)。此真实 对象将是getDelegate()
的值。如果 getDelegate()
的值在 secondEjb.doSomething()
和 thirdEjb.doSomething()
中不相同 (==) 那么您没有获得预期的传播,并且每个人都在与不同的持久性上下文对话。
请注意,在类上应用 MANDATORY 实际上只会影响在该类中定义的方法,而不影响在父类(super class)中定义的方法。如果您没有在父类(super class)上指定 @TransactionAttribute,那么无论子类如何注释,这些方法都使用默认值。我只提到这一点,因为它可能会影响您对代码的理解。
关于java - 了解 EJB3/JPA 容器级事务和隔离级别,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4136852/