javax.transaction.Transactional与org.springframework.transaction.annotation.Transactional的区别

246
我不明白javax.transaction.Transactionalorg.springframework.transaction.annotation.Transactional之间的实际区别是什么? org.springframework.transaction.annotation.Transactional是否是javax.transaction.Transactional的扩展,还是它们完全具有不同的含义?应该在什么情况下使用每个注解?服务层中的Spring @Transactional和DAO中的javax
谢谢回答。
4个回答

190

Spring多年前就定义了自己的Transactional注解,将Spring bean方法设置为事务性。

Java EE 7终于也做到了同样的事情,并且现在允许CDI bean方法成为事务性,除了EJB方法。因此,从Java EE 7开始,它也定义了自己的Transactional注解(显然不能重用Spring的)。

在Java EE 7应用程序中,您将使用Java EE注解。

在Spring应用程序中,您将使用Spring注解。

它们的使用方式相同:通知容器(Java EE或Spring)一个方法是事务性的。


57
除此之外,为了统治宇宙,Spring还隐式支持了 javax.transaction.Transactional,因此现在可以在Spring应用程序中使用它而无需任何其他操作。依我看,从设计的角度来看,这是一个相当糟糕的决定,因为根据我的经验,许多开发人员会在代码中不自觉地混淆这两个概念,导致后续问题。 - Yuriy Nakonechnyy
34
此外,org.springframework.transaction.annotation.Transactional 提供的选项(如 readOnlytimeout)比 javax.transaction.Transactional 更多。 - pierrefevrier
3
@yura,你观察到了哪些问题? - Lee Chee Kiam
2
@LeeCheeKiam 请查看下面的两个答案。 - Yuriy Nakonechnyy
“Java EE 7终于做到了同样的事情”这句话非常误导人:这个注解自EJB 3.0以来就存在了,实际上与Spring在1.2时期拥有这样的注解(同时) 。当这篇文章发表时,CDI的支持还是相当“新”的(但CDI也是如此)。 - ymajoros

68

另一个区别是Spring如何处理@Transactional注解:

  • org.springframework.transaction.annotation.Transactional 总是被考虑在内。
  • 只有当存在EJB3事务时,javax.transaction.Transactional 才会被考虑。检查是否存在EJB3事务是通过检查类路径中是否有 javax.ejb.TransactionAttribute 类(从版本2.5.3到3.2.5)来完成的。 因此,如果你的类路径中只有javax.transaction.Transactional 而没有 javax.ejb.TransactionAttribute,那么你的注解可能不会被考虑。这种情况可能会出现在使用Hibernate时:hibernate-core (4.3.7.Final) 依赖于 jboss-transaction-api_1.2_spec (1.0.0.Final),后者不提供javax.ejb.TransactionAttribute

14
我认为这已经不是问题了,因为在Spring 4.2.0中,javax.transaction.Transactional注解也被支持作为Spring自己注解的替代品 - Arend v. Reinersdorff
如果它在私有方法中,例如,它不会被执行。 - strash

63

声明式事务范围

Spring和JPA的@Transaction注解允许你定义给定应用程序事务的范围。

因此,如果一个服务方法被标记了@Transactional注解,则它将在事务上下文中运行。如果服务方法使用多个DAO或Repository,所有的读写操作都将在同一个数据库事务中执行。

Spring @Transactional

org.springframework.transaction.annotation.Transactional注解自Spring框架1.2版本(约2005年)就可用了,它允许你设置以下事务属性:

  • isolation:底层数据库隔离级别
  • noRollbackFornoRollbackForClassName:可以触发而不会导致事务回滚的Java Exception类列表
  • rollbackForrollbackForClassName:在抛出时触发事务回滚的Java Exception类列表
  • propagation: 由Propagation枚举给出的事务传播类型。例如,如果事务上下文可以继承(例如REQUIRED)或应创建新的事务上下文(例如REQUIRES_NEW),或者如果没有事务上下文,则应抛出异常(例如MANDATORY),或者如果发现当前存在事务上下文,则应抛出异常(例如NOT_SUPPORTED)。
  • readOnly: 当前事务是否只读取数据而不进行任何更改。
  • timeout: 事务上下文允许运行多少秒,直到抛出超时异常。
  • valuetransactionManager: Spring TransactionManager bean 的名称,在绑定事务上下文时要使用。
  • Java EE @Transactional

    javax.transaction.Transactional注释是由Java EE 7规范(大约在2013年)添加的。因此,与Spring的对应版本相比,Java EE注释晚了8年。

    Java EE的@Transactional仅定义了3个属性:
    • dontRollbackOn:可以触发异常但不会触发事务回滚的Java Exception类列表
    • rollbackOn:抛出时会触发事务回滚的Java Exception类列表
    • value:由TxType枚举给出的传播策略。例如,如果事务上下文可以继承(如REQUIRED),或者应该创建一个新的事务上下文(如REQUIRES_NEW),或者如果没有事务上下文存在则抛出异常(如MANDATORY),或者如果找到当前事务上下文则抛出异常(如NOT_SUPPORTED)。

    如何选择?

    如果您在使用Spring或Spring Boot,则使用Spring的@Transactional注解,因为它允许您配置比Java EE的@Transactional注解更多的属性。

    如果您仅使用Java EE,并且将应用程序部署在Java EE应用程序服务器上,则使用Java EE的@Transactional注解。


    Java/Jakarta EE的@Transactional注解是否适用于private方法? - Dina Bogdan
    2
    很可能不是。当从不同的层调用服务时,例如Web或计划程序,事务边界应该开始。 - Vlad Mihalcea
    实际上,我已经在同一个类中有一个委托方法,并且该方法带有@Transactional注释。我知道我可以将注释移动到此委托方法中,但我对此很好奇,而且在网上也没有找到任何相关信息。 - Dina Bogdan
    3
    私有方法不计算在内。只有服务间方法才会被传播规则计算。 - Vlad Mihalcea

    45
    请注意,(此问题发生在tomcat中)。
    如果您的应用程序是SPRING Web应用程序并且正在使用Spring的事务处理机制,即@org.springframework.transaction.annotation.Transactional,请勿与javax.transaction.Transactional混合使用。
    也就是说,在Spring应用程序中始终要一致地使用@org.springframework.transaction.annotation.Transactional
    否则,我们可能会遇到这个错误。
    org.springframework.orm.jpa.JpaSystemException: commit failed; nested exception is org.hibernate.TransactionException: commit failed
    
    ........
    
    Caused by: java.sql.SQLException: Protocol violation: [0]
    

    2
    注意:此答案是我回答的一个特殊情况。 - Jidehem

    网页内容由stack overflow 提供, 点击上面的
    可以查看英文原文,
    原文链接