CDI 事务管理

Posted

技术标签:

【中文标题】CDI 事务管理【英文标题】:CDI transaction management 【发布时间】:2015-07-06 18:19:48 【问题描述】:

我正在进行从 JBoss Seam 到 CDI 的迁移项目。 以下是技术栈:

1)WildFly 8.2.0(CDI 1.2,Weld 作为 CDI 提供者)

2)JSF 2.2

3)JPA 2

我们正在使用容器管理的 JTA 事务:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
   xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
   <persistence-unit name="surveillenace" transaction-type="JTA">
    <provider>org.hibernate.jpa.HibernatePersistenceProvider</provider>
    <jta-data-source>java:/surveillenaceDS</jta-data-source> 


    <!-- other configurations not shown here -->

</persistence>

并使用@PersistenceContext注解将EntityManager注入DAO对象。

我们正在使用@Transaction 注释进行容器管理事务。

我的问题/理解如下。

谁能证实这一点,因为这对我来说是一个相对较新的领域。

1)据我了解,CDI 通过@Transaction 拦截器提供对 CMT 的支持。哪个类/依赖项实际上实现了这个拦截器? 我们需要在 pom.xml 中为此导入哪些工件?

2)由于使用了CMT,我们不需要划分任何事务,容器将管理它。我们只需要使用 EntityManager API 来持久化 Db 中的更改。 这种理解正确吗?

 @Transactional
    public String finishOperation() 
        log.debug("in finishOperation() ") ;
        try    
        //operations done on managed entities 
        //no transaction demarcation code is required here 
        dao.getEntityManager.commit();      

    catch(Throwable xx)
    
    

3)考虑以下使用上述配置执行的简单场景:

Component1.somemethod() - 在事务内部运行并持久化一个实体(例如:用户)并提交事务。 在此之后,Component2 被如下调用:Component2.somemethod() - 在事务内部运行,但实体 User 似乎并未处于托管状态,即 em.contains(user) 返回 false。 我必须再次合并此实体以使其管理或再次从持久存储重新加载

由于 Seam 使用 conversation-scoped entity manager ,所有实体实例都保持在托管状态(在持久上下文中),即使任何组件提交事务并且之后调用另一个组件。 但在 CDI 案例中,据我了解,这是由于 "transaction scoped entity manager" 而发生的。一旦事务提交,所有实体实例都会分离。 我们如何使用 CDI 实现与 Seam 相同的效果?

【问题讨论】:

【参考方案1】:

回答您的问题并澄清在您使用 Java EE 7 / CDI 1.2 时仅针对 Java EE 6 / CDI 1.0 的先前答案

    CDI 不实现事务,但 JTA 规范可以。是的,JTA 定义了拦截器绑定@Transactional,并且实现必须提供匹配的拦截器。当您在 WildFly 下时,您的问题的答案在 JBoss JTA 实现中:Narayana。你会找到@Transactional(Required) 拦截器here。其他人在同一个包中。 是的,您的理解是正确的。 Extended Persistence context 只能在 EJB Stateful session bean 中注入。在 Java EE 7 中,您可以尝试使用新的 JPA 2.1 Unsyncrhonized mode(未在 CDI 中测试)。

【讨论】:

当然你是对的,我的立场是正确的,我意识到 J EE 7 提供了@Transactional 拦截器,我想我出于某种原因正在考虑 CDI 1.0,抱歉以某种方式误导了答案 @mariubog 然后你应该在你的答案顶部添加一个免责声明:)【参考方案2】:

CDI 不提供事务管理实现作为其规范的一部分。事务管理留给程序员通过拦截器来实现,拦截器将处理所有基础知识,如开始提交等。

通常 EntityManager 存在于事务的时间跨度内。在 seam 2 中,您具有扩展的持久性上下文,因此它在多个请求中保持状态和 bean 附加到它。 CDI 不提供,而且由于可扩展性的原因,它不建议这样做。如果您查看 DeltaSpike,我强烈建议您在从 Seam2 迁移到 CDI 的情况下,他们提供延长 EntityManager 寿命的选项,将其提升到对话范围,但他们也不推荐这种方法。


这里有 DeltaSpike 处理您的问题的文档:

https://deltaspike.apache.org/documentation/jpa.html#ExtendedPersistenceContexts

Deltaspike 是一个很好的绑定解决方案,文档非常短,所以我会在你的情况下推荐它,此外它是由具有接缝背景的人创建的,并提供开箱即用的事务管理。

【讨论】:

您的答案在 Java EE 6 中是正确的,但在 Java EE 7 中是错误的。JTA 1.2 提供了@Transactional 拦截器绑定和拦截器实现。

以上是关于CDI 事务管理的主要内容,如果未能解决你的问题,请参考以下文章

如何在 CDI 环境中管理 EntityManager 生命周期(使用 Tomcat)

181 - flowable-cdi流程bean管理流程事件

180 - flowable-cdi流程bean管理

180 - flowable-cdi流程bean管理

181 - flowable-cdi流程bean管理流程事件

如何在 CDI 中使用 MyBatis