Spring的事务传播机制(大白话)
作者:互联网
什么叫做Spring的事务机制?
Spring自身没没有什么事务机制,只是连接的是Mysql这样的支持事务的数据库时,在对Mysql数据库进行一系列的增删改操作的时候,就需要合理使用Mysql的事务机制。
Spring的事务实现方式是通过AOP实现的,比如一个A方法上面标注了@Transactional,A方法里面有对Mysql数据库的操作,那么通过AOP实现事务的方式就是:在执行A方法之前发出begin trancation,在执行A方法之后,如果没有报错,就发出commit,如果有报错就发出rollback给Mysql。
那么所谓的Spring的事务机制,就是说如何把begin transaction、commit 、rollback这些sql语句在"合适的时机"发给Mysql,OK,那么对这个“合适的实际”的把控与管理,就叫做Spring的事务机制了。
那什么又叫做Spring的事务传播机制呢?
比如代码中A方法调用了B方法,A方法、B方法上都标注了@Transactional,那么问题来了:A方法里对发给Mysql的sql语句应该和B方法里的在一个事务里吗?也就是说是在A方法、B方法执行之前都发begin transaction,执行之后都发commit,还是说只需要在A方法执行之前发begin transaction,在A方法执行之后发rollback呢?好,如何处理这样的问题,这就是Spring的事务传播机制。
Spring传播机制:
查看@Transactional的源码:
其中Propagation指的是事务传播方式的枚举类,点进去看看:
这便是Spring事务传播机制的几种方式了,以下一一进行介绍:
REQUIRED:
如果当前没有事务,则新建一个事务;如果当前有事务,则加入当前事务。这是默认的传播方式。
比如A方法调用了B方法,其中B方法标注了@Transactional,如果A方法当前没有事务,就在执行B方法的时候新建一个事务,也就是通过AOP,在执行B方法之前发一个begin transaction给Mysql,在执行B方法之后发一个commit给Mysql(如果执行没有报错的话);如果A方法当前已经在一个事务中了,那么在执行B方法前后不做任何处理。
REQUIRES_NEW:
无论当前是否存在事务,都要新建事务。如果当前存在事务,把当前事务挂起,当把新建的事务执行完毕并提交之后,再把当前事务从挂起中恢复出来,继续执行。
比如A方法调用了B方法,其中B方法标注了@Transactional(propagation = Propagation.REQUIRES_NEW),那么无论当前是否存在事务,会通过AOP的方式,在执行B方法之前发一个begin transaction 给Mysql,在执行B方法之后,发一个commit给Mysql(如果执行没有报错的话)。
NESTED:
嵌套事务。如果当前存在事务,则在嵌套事务内执行;如果当前没有事务,则新建一个事务。
这里说“嵌套”其实是Spring的说法,因为方法调用的缘由吧,其实实际依赖的是Mysql的savepoint、rollback to,在Mysql看来,更像是在一个事务中回滚到某个保存点。
比如A方法调用B方法,其中B方法标注了@Transactional(propagation = Propagation.NESTED),如果A方法没有事务,则在执行B方法之前发出begin transaction,执行之后发送commit(如果执行没有报错的话);如果A方法有事务,则在执行B方法之前发出savepoint x;在执行B方法之后,如果顺利,则什么都不做,如果在执行B方法中抛出了异常(默认为RuntimeException),则发出rollback to x;
SUPPORTS:
支持当前事务。如果当前没有事务,就以非事务方式执行;如果当前有事务,则加入。
比如A方法调用了B方法,其中B方法上标注了@Transactional(propagation = Propagation.SUPPORTS),不管A方法有没有事务,在执行B方法前后都不做任何处理。
MANDATORY:
使用当前的事务。如果当前没有事务,就抛出异常;如果当前有事务,则加入。
比如A方法调用了B方法,其中B方法上标注了@Transactional(propagation = Propagation.MANDATORY),如果A方法有事务,则执行B方法前后不做任何处理,如果A方法没有事务,则通过AOP的方式,在执行B方法之前抛出指定的异常。
NOT_SUPPORTED:
以非事务方式执行。如果当前没有事务,则正常执行;如果当前存在事务,就把当前事务挂起。
NEVER:
以非事务方式执行。如果当前没有事务,则正常执行;如果当前存在事务,则抛出异常。
嵌套事务的意义:
如果程序正常执行,没有抛出RuntimeException,也就不会涉及到回滚,那么嵌套事务不会有特殊之处,NESTED的特殊之处,在于涉及到回滚的场景:A方法调用B方法,其中B方法标注了@Transactional(propagation = Propagation.NESTED),如果B方法抛出RuntimeException,那么只会对B方法中的操作进行回滚,而不影响到A方法中的其他操作。
好,利用这个特性,就可以使用在某些场景中,比如:A方法中调用了B方法、C方法,如果B方法执行失败,则调用C方法。实现方式就是:如果B方法执行失败,对B方法进行回滚,同时A方法并不回滚,在A方法代码中捕获这个异常,然后在异常分支中调用C方法。
局限性:
Spring事务机制只限于单应用内,不支持分布式事务!
标签:事务,大白话,Spring,当前,Mysql,执行,方法 来源: https://blog.csdn.net/weixin_35794878/article/details/122508596