java - EJB/JPA 事务边界

标签 java hibernate jpa transactions ejb-3.0

我在读
EJB Transaction boundary and Transaction boundary

让我们专注于RequiresNew Attribute .

这是链接中的修改图

enter image description here

所以说method-BRequiredNew attribute 注释.

所以根据理论当method-A电话method-B一个新的事务将开始,已经开始的事务将被暂停,当 method-B返回新事务将被提交。

现在考虑在 S1 部分我们使用 entitymanager.persist() 创建一个 jpa 实体现在我们将此实体传递给 method-B其中设置了 name实体的领域。

现在当我们从 method-B 返回时怎么可能commit db 中的事务,实体没有被 method-A 启动的挂起事务提交?

PS:在读提交隔离级别运行的数据库。

最佳答案

在这种情况下发生的事情由以下因素控制:

  • JPA 持久上下文及其与 JTA 事务的关系。
  • Java 的“引用传递”行为,如在本地接口(interface)上传递参数。
    (请参阅本答案末尾关于通过引用传递的注释)

  • 使用 @PersistenceContext 创建实体管理器注释导致创建一个事务范围的实体管理器和相关的持久化上下文,如您的 persistence.xml 所定义的。文件。上下文将跟踪您的 persistence.xml 中指定的类型的实体。 .实体在持久化、找到 ( em.find() ) 或合并后,将在该上下文中进行管理。上下文将与当前运行的 JTA 事务相关联。当此事务结束时,持久性上下文中存在的更改可以刷新并提交 - 如果事务本身回滚,则可以回滚。

    在示例场景中,假设使用了 Bean2 的本地接口(interface)。当Bean2-MethodB被称为新事务已启动,因为该方法用 @TransactionAttribute(TransactionAttributeType.REQUIRES_NEW) 注释。 .调用方法的事务被挂起。没有持久性上下文与新创建的事务相关联。但是,传入的实体将引用由 Bean1-MethodA 处理的实体的同一实例。 ,并且这个实例是 Bean1 的实体管理器的持久化上下文中的一个托管实体。因此,即使与此持久性上下文关联的事务被挂起,从另一个事务中修改该实体也没有限制。

    所以,名义上的事件顺序是;
  • Bean1-MethodA被调用,TransactionA 开始。
  • 事务范围实体管理器创建,与事务A 关联的持久化上下文。
  • Bean1-MethodA电话Bean2MethodB并将“实体”作为参数传入。
  • 新事务 – 事务 B 开始,事务 A 暂停。
  • Bean2-MethodB修改字段 entity.name .
  • Bean2-MethodB 完成并且 TransactionB 提交。
  • TransactionB JTA 持久资源提交 - 实体在与 TransactionA 关联的持久上下文中,因此未提交。
  • Bean1-MethodA 与其关联的 TransactionA 一样恢复。
  • 实体更改 Bean2-MethodBBean1-MethodA 可见和持久化上下文
  • Bean1-MethodA完成,TransactionA 提交和持久性上下文更改刷新/提交到 DB
  • --> DB 包含在 Bean2-MethodB 中所做的字段更改

  • 当 Bean2-MehodB 的 Transaction 回滚时会发生什么?

    值得注意的是,如果实体字段在Bean2-MethodB中进行了更改, 和 Bean2-MethodB’s事务回滚,对类字段的更改不会恢复。任何 JTA 资源都将回滚,但实体字段更改仍将反射(reflect)在数据库中 If Bean1-MehodA成功完成,导致潜在的不一致。也许现实世界的问题可能会迫使这样的解决方案,但可能更好的是修改事务中可以回滚这些更改的实体。

    以上场景在eclipse-mars/WildFly8.2/HibernateJPA/Derby 上测试过

    使用远程 EJB 调用

    在这里,实体参数被序列化,导致 Bean2-MethodB 中的实体副本。 .此副本与 Bean1-MethodA 中使用的对象不同,它是一个分离的实体,不与 Bean1-MethodA 共享. (这有时称为传值,请参阅本答案末尾的注释)。为了在 Bean1-MethodA’s 中反射(reflect)更改实体需要返回到 Bean1-MethodA 的持久性上下文然后使用实体管理器合并到持久性上下文中。无论远程 ejb 调用是否在事务中进行,都需要进行这种合并。

    注意“传递引用”和“传递值”。

    java中的所有参数都是按定义传递的。有关堆栈溢出的良好扩展讨论,请参阅 Is Java "pass-by-reference" or "pass-by-value"? .这里重要的是,对于本地接口(interface),Java 将引用的副本——一个指针——传递给共享实例——这就是人们通常理解的“传递引用”。远程接口(interface)在远程端创建实体实例的副本,因此调用方法无法看到对此副本的任何更改。这有时称为传值。

    关于java - EJB/JPA 事务边界,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30636273/

    相关文章:

    java - 将html代码插入到sql中

    java - 如何在创建实例后初始化 BigInteger(无法调用构造函数)

    java - 比较来自加速度计的 3D 信号数据的算法

    xml - Hibernate 写入 XML 数据库

    java - Dropwizard hibernate 搜索

    java - JavaFX:基于属性的实体与基于属性的包装器

    java - Hibernate 是否支持 Postgres 9.2 Json 数据类型?

    java - 如何使用扫描仪逐行读取文件并使用信息?

    java - Eclipselink 进入错误的数据库平台

    java - JPA 惰性插入