代码之家  ›  专栏  ›  技术社区  ›  Steve Perkins

了解EJB3/JPA容器级事务和隔离级别

  •  6
  • Steve Perkins  · 技术社区  · 15 年前

    @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 doSomething() 必须在提供的事务中调用。在这种情况下,我们使用容器管理的事务。

    这个 根本不用 SecondEjbType ThirdEjbType ... 既不在类级别,也不在方法级别。我明白这意味着 secondEjb.doSomething() thirdEjb.doSomething() 两者都将在为 firstEjb.doSomething() .

    某物 ! 如代码注释所示。。。 secondEjb 将数据写入数据库,并且 thirdEjb 作为其操作的一部分读取该数据。因为所有这些都在同一事务中运行,所以我不希望隔离级别有任何问题。 第二个ejb 数据库写入对不可见 三分贝

    我已经将跟踪一直转到最大值,显然没有异常、错误或回滚的问题。。。初始写入对后续读取是不可见的。我并不自称是世界上最伟大的交易管理大师。。。我是否漏掉了一些显而易见的东西,或者我的概念理解基本正确,问题可能就在别处?


    • 我在跑玻璃鱼
    • 我不知道你说的“非标准刷新模式”是什么意思,所以我认为答案是否定的。
    • 我的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>

    5 回复  |  直到 15 年前
        1
  •  15
  •   David Blevins    15 年前

    首先要检查的是豆子2和豆子3的用途 @PersistenceContext EntityManager 让实体管理器和 @PersistenceUnit EntityManagerFactory createEntityManager() 打电话来。

    其次,检查 DataSource 实际设置为参与JTA事务(应关闭自动提交或相关属性)。

    最后,检查传播的一个快速而肮脏的方法是调用 EntityManager.getDelegate() 方法并检查结果对象是 相同的

    下面是事情在幕后的运作方式。。。。这个 EntityManager 在创建bean时注入它是一个假的、简单的外观。当您试图在事务中使用EntityManager引用时,容器实际上会在当前事务中进行挖掘,找到 存放在事务作用域中并将调用委托给 EntityManager(如果事务中没有EntityManager,则容器将创建一个并添加它)。这个 真实的 getDelegate() . 如果 获取委托() 与中的(==)不同 secondEjb.doSomething() thirdEjb.doSomething()

    另一方面,请注意,对类应用强制实际上只影响在该类中定义的方法,而不是在超级类中定义的方法。如果未在超级类上指定@TransactionAttribute,则无论子类如何注释,这些方法都使用默认值。我只提到这一点,因为它可能会影响您对代码的理解。

        2
  •  12
  •   Pascal Thivent    15 年前

    我已经在类级别将TransactionAttribute注释设置为强制性。我理解这意味着必须在提供的事务中调用所有方法,如doSomething()。在这种情况下,我们使用容器管理的事务。

    使用 MANDATORY 在类级别,意味着容器应该向调用方抛出一个异常,如果没有正在进行的事务,则 FirstEjbType 被称为。

    REQUIRED ?

    TransactionAttribute在SecondEjbType或ThirdEjbType中根本没有使用。。。既不在类级别,也不在方法级别。我理解这意味着secondEjb.doSomething()和thirdEjb.doSomething()都将在为firstEjb.doSomething()提供的事务中操作

    必修的 ,和 如果 必须)。

    secondEjb.doSomething() thirdEjb.doSomething() 确实应该在 firstEjb.doSomething() .

    我是否漏掉了一些显而易见的东西,或者我的概念理解基本正确,问题可能就在别处?

    (事务作用域)持久性上下文传播的经验法则是,持久性上下文随着JTA事务传播而传播。但也有一些限制。JPA规范如下:

    5.6.3持久性上下文传播

    持久性上下文可以对应于 实例(所有与 同一实体管理器工厂)。

    跨实体管理器实例

    持久性上下文的传播 地方的 环境。持久性上下文是

    而Sahoo(来自GlassFish团队)在 Persistence Context propagation :

    因此,假设您在任何地方都使用JPA,我希望在同一事务中调用的业务方法只继承相同的持久性上下文 Remote 接口

    PS:JPA假设 READ_COMMITTED 隔离级别(所以乐观锁定可以工作)和标准JPA不允许对隔离级别进行自定义设置(好吧,一些提供程序允许全局或按请求更改隔离级别,但这是不可移植的)。

    PPS:

    工具书类

      • 第5.6.3节“持久性上下文传播”
        3
  •  2
  •   axtavt    15 年前

    自从 thirdEjb 方法,因此更改不会写入数据库。

    默认情况下,JPA持久性上下文在提交之前、执行JPA查询之前或使用 em.flush() 三分贝 -例如,如果使用JDBC读取数据,则在没有 .

        4
  •  1
  •   Arjan Tijms Mike Van    12 年前

    你需要提供更多的信息来回答这个问题。

    • 是否设置了非标准刷新模式?
    • 你能发布persistence.xml文件吗?

    交易

    根据EJB 3.0,所有ejb3.0应用程序的默认事务属性是 REQUIRED . 交易类型的单据如下: http://download.oracle.com/javaee/6/api/javax/ejb/TransactionAttributeType.html

    你可能在用 REQUIRES_NEW

    特别是,尝试对第2和第3个ejb使用本地接口而不是远程接口 .

    使用默认设置,在查询之前强制刷新(如果需要)以确保结果正确: http://download.oracle.com/javaee/5/api/javax/persistence/FlushModeType.html

    试着打电话 entityManager.setFlushMode(FlushModeType.AUTO); 以确保在查询之前发生刷新。在JPA提供程序中启用SQL日志记录,以确保更新/插入确实在选择之前发送到DB。

        5
  •  0
  •   Steve Perkins    15 年前

    从一个EJB跳到另一个EJB并没有任何关系。为了简化问题,我尝试使用与一个EJB完全隔离的测试用例。我是这么想的 secondEjb.doSomething() 方法,它将实体持久化到数据库。在方法的末尾,我添加了 em.flush()

    即使我是 ,它对随后的查询不可见。我已经做了 some additional research elsewhere ,看起来这可能只是事务上下文中JPA的正常隔离模式。当事务启动时,该事务中的其他查询还不能看到未提交的数据。