Spring事务传播机制

对事务的学习总体来讲应该包含以下几个部分:

  1. 事务的概念:数据库层面的,简单了解什么是事务,以及隔离级别、事务的提交、回滚、保存点等基本概念。
  2. 动态代理以及Spring AOP,是Spring框架实现事务控制的底层技术基础。
  3. Spring框架事务的实现方式。
  4. Spring框架事务实现的底层原理。

可以循序渐进逐步学习,也可以单独学习其中某一部分,但是只有全部彻底掌握了,才能对事务有一个全局的了解。

一般来讲,程序员实现事务控制有两种选择:编程式事务、声明式事务。从代码编写的角度讲,编程式事务太麻烦,现在用的很少了,20年前的程序员绝大部分用的都是编程式事务,非常麻烦,需要自己获取连接、开启事务、提交或回滚事务、关闭连接等。

声明式事务是基于AOP实现的,现在JAVA世界的绝大部分项目都是基于Spring框架实现的,Spring框架、尤其是Springboot框架对事务管理的支持非常友好,使用非常简单。

Spring框架实现事务控制其实非常简单,主要的注解只有两个:

  1. @EnableTransactionManagement
  2. @Transactional

@EnableTransactionManagement注解是负责在配置类中打开Spring的事务管理功能,@Transactional是具体负责开启及实现事务控制的。从应用层面来讲,@Transactional是学习的重点。

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Transactional {
    @AliasFor("transactionManager")
    String value() default "";

    @AliasFor("value")
    String transactionManager() default "";

    String[] label() default {};

    Propagation propagation() default Propagation.REQUIRED;

    Isolation isolation() default Isolation.DEFAULT;

    int timeout() default -1;

    String timeoutString() default "";

    boolean readOnly() default false;

    Class<? extends Throwable>[] rollbackFor() default {};

    String[] rollbackForClassName() default {};

    Class<? extends Throwable>[] noRollbackFor() default {};

    String[] noRollbackForClassName() default {};
}

@Transactional的重要属性包括:

  1. 事务传播机制Propagation
  2. 隔离级别isolation
  3. 等待超时时间timeout
  4. 回滚条件rollbackFor
  5. 不回滚条件noRollbackFor

其实Spring事务管理是重度依赖于数据库底层的支持的,尤其是类似隔离级别、等待超时时间等概念,都是直接依赖于数据库底层去实现的,Spring事务管理其实什么都不需要干,只需要把配置好的属性传递给数据库连接、交给数据库去完成即可。

而事务传播机制Propagation与其他特性不同,是spring框架事务管理功能的重头戏。事务传播机制负责控制不同事务发生的时候,上层事务与下层事务之间的关系。

Spring定义了以下7种事务传播机制:

REQUIRED

Support a current transaction, create a new one if none exists. Analogous to EJB transaction attribute of the same name.
This is the default setting of a transaction annotation.

需要启用事务,当前不存在事务的话,就创建一个新事务,如果存在事务的话,则加入。

这是Spring的默认传播机制。

比如事务控制的经典案例银行转账交易:转账交易由转出和转入两部分功能组成,如果我们按照如下方式实现的话:

@Transactional
public void transfer(Acct acct1,Acct acct2){
    withdrawl(acct2);
     deposit(acct1);
}
@Transactional(propagation=Propagation.REQUIRED)
public void deposit(){
    acct1.deposit();
}
@Transactional(propagation=Propagation.REQUIRED)
public void withdrawl(){
   acct2.wiwithdrawl();
}

转出和转入方法就必须要启用事务、事务传播机制可以设置为REQUIRED,那么在转出交易调用的时候,因为transfer方法已经开启了一个事务,所以,转出方法withdrawl不再开启新事物、而是使用已经存在的事务,同样,转入方法deposit也使用该事务。这样,转出交易和转入交易就被包含在了同一个事务中,能够实现要么全部成功、要么全部失败的交易目标。

SUPPORTS

Support a current transaction, execute non-transactionally if none exists. Analogous to EJB transaction attribute of the same name.
Note: For transaction managers with transaction synchronization, SUPPORTS is slightly different from no transaction at all, as it defines a transaction scope that synchronization will apply for. As a consequence, the same resources (JDBC Connection, Hibernate Session, etc) will be shared for the entire specified scope. Note that this depends on the actual synchronization configuration of the transaction manager.
See Also:
org.springframework.transaction.support.AbstractPlatformTransactionManager.setTransactionSynchronization

当前如果已经开启了事务的话,则加入,如果没有已经开启的事务的话,也无所谓,当前方法不开启事务。

MANDATORY

Support a current transaction, throw an exception if none exists. Analogous to EJB transaction attribute of the same name.

当前方法被调用的时候必须有事务,如果没有已经开启的事务的话,就不干,抛异常。

上面银行转账交易,也可以采用MANDATORY。

REQUIRES_NEW

Create a new transaction, and suspend the current transaction if one exists. Analogous to the EJB transaction attribute of the same name.
NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager, which requires the javax.transaction.TransactionManager to be made available to it (which is server-specific in standard Java EE).
See Also:
org.springframework.transaction.jta.JtaTransactionManager.setTransactionManager

启用新事务,如果当前已经存在一个事务的话,则挂起该事务。

被挂起的事务不会受到开启的新事务执行结果的影响,无论新事务被提交还是被回滚。

NOT_SUPPORTED

Execute non-transactionally, suspend the current transaction if one exists. Analogous to EJB transaction attribute of the same name.
NOTE: Actual transaction suspension will not work out-of-the-box on all transaction managers. This in particular applies to org.springframework.transaction.jta.JtaTransactionManager, which requires the javax.transaction.TransactionManager to be made available to it (which is server-specific in standard Java EE).
See Also:
org.springframework.transaction.jta.JtaTransactionManager.setTransactionManager

不启用事务,如果当前已经存在一个事务的话则挂起当前事务。

NEVER

Execute non-transactionally, throw an exception if a transaction exists. Analogous to EJB transaction attribute of the same name.

不启用事务,如果当前已经存在一个事务的话就抛出异常。

NESTED

Execute within a nested transaction if a current transaction exists, behave like REQUIRED otherwise. There is no analogous feature in EJB.
Note: Actual creation of a nested transaction will only work on specific transaction managers. Out of the box, this only applies to the JDBC DataSourceTransactionManager. Some JTA providers might support nested transactions as well.
See Also:
org.springframework.jdbc.datasource.DataSourceTransactionManager

嵌套事务,如果当前已经存在一个事务的话,则行为类似于REQUIRED。注意:嵌套事务仅针对特定的事务管理器,需要特定事务管理器的支持,是否生效取决于JDBC数据源的事务管理器。

嵌套事务的实际含义是:如果当前存在一个事务的话,则保存当前事务的savepoint(保存点),并加入事务,如果当前不存在事务的话,就启用一个新事务。

嵌套事务实际使用了数据库的savepoint,需要数据库支持savepoint,如果数据库不支持savepoint,那么这个NESTED也就不会生效。

savepoint的意思对当前事务已经执行的数据库操作记录一个保存点,新方法加入事务后,如果执行成功则一起提交,如果执行失败则只回滚新方法的操作,不回滚保存点以前的数据库操作。

以上Spring提供的7种事务传播机制,我们应该都有所了解。但是,实际应用场景中能用到的,或者用的比较多的,也就REQUIRED、以及REQUIRED_NEW。一般情况下REQUIRED足够满足需要了,有些应用框架需要记录操作日志,审计用,不论操作成功还是失败都需要记录。这种情况下,REQUIRED_NEW即可。

全部评论

相关推荐

不愿透露姓名的神秘牛友
05-29 15:00
教授A:“你为什么要讲这么久,是要压缩我们对你的评议时间吗?你们别以为这样就能够让我们对你们少点意见。”&nbsp;“从你的发言和论文格式就能知道你的性格啊。”…….&nbsp;感觉被狠狠霸凌了。
码农索隆:“教授您好,首先我想回应您提出的两点疑问。” “关于我讲解时间较长的问题:这绝非为了压缩各位老师的评议时间。这份毕业设计是我过去几个月倾注了全部心血的作品,从构思、实验、调试到撰写,每一个环节都反复打磨。我深知时间宝贵,所以选择详细讲解,是希望能更完整、清晰地展示它的核心创新点、实现过程和验证结果,确保老师们能充分理解它的价值和我的努力。我完全理解并重视评审环节的意义,也做好了充分准备来听取各位老师的专业意见和批评。几个月的研究都坚持下来了,我怎么可能害怕老师们的点评呢?今天站在这里,正是抱着虚心学习、诚恳求教的态度而来。” “如果我的展示确实超时,影响了后续流程,烦请老师们随时示意,我会立刻调整。我非常期待并预留了充足的时间,希望能听到老师们宝贵的建议和深入的讨论。” “其次,关于您提到‘从发言和论文格式就能知道我的性格’。教授,我对此感到非常困惑和不安。学术研究和答辩的核心,难道不应该是作品本身的质量、逻辑的严谨性、数据的可靠性和结论的合理性吗?论文格式有明确的规范要求,我尽最大努力遵循了这些规范。如果格式上存在疏忽或不足,这属于技术性、规范性的问题,恳请老师们具体指出,我一定认真修改。但将格式问题或个人表达风格(如讲解时长)直接上升为对个人性格的评判,甚至以此作为质疑我学术态度和动机的依据,这让我感到非常不公平,也偏离了学术评议应有的客观和严谨原则。” “我尊重每一位评审老师的专业权威,也衷心希望能得到老师们对我的工作内容本身的专业指导和批评指正。任何基于研究本身的意见,无论多么尖锐,我都会认真聆听、反思并改进。但我恳请老师们,能将评议的焦点放在我的研究本身,而不是对我个人进行主观的推断或评价。谢谢各位老师。”
点赞 评论 收藏
分享
迷茫的大四🐶:自信一点,我认为你可以拿到50k,低于50k完全配不上你的能力,兄弟,不要被他们骗了,你可以的
点赞 评论 收藏
分享
评论
2
7
分享

创作者周榜

更多
牛客网
牛客企业服务