Spring事务的传播

PROPAGATION_REQUIRED    表示当前方法必须运行在事务中。如果当前事务存在,方法将会在该事务中运行。否则,会启动一个新的事务。
PROPAGATION_SUPPORTS    表示当前方法不需要事务上下文,但是如果存在当前事务的话,那么该方法会在这个事务中运行。
PROPAGATION_MANDATORY    表示该方法必须在事务中运行,如果当前事务不存在,则会抛出一个异常。
PROPAGATION_REQUIRED_NEW    表示当前方法必须运行在它自己的事务中。一个新的事务将被启动。如果存在当前事务,在该方法执行期间,当前事务会被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager。
PROPAGATION_NOT_SUPPORTED    表示该方法不应该运行在事务中。如果存在当前事务,在该方法运行期间,当前事务将被挂起。如果使用JTATransactionManager的话,则需要访问TransactionManager。
PROPAGATION_NEVER    表示当前方法不应该运行在事务上下文中。如果当前正有一个事务在运行,则会抛出异常。
PROPAGATION_NESTED    表示如果当前已经存在一个事务,那么该方法将会在嵌套事务中运行。嵌套的事务可以独立于当前事务进行单独地提交或回滚。如果当前事务不存在,那么其行为与PROPAGATION_REQUIRED一样。注意各厂商对这种传播行为的支持是有所差异的。可以参考资源管理器的文档来确认它们是否支持嵌套事务。

而事务的 ACID 是通过 InnoDB 日志和锁来保证。事务的隔离性是通过数据库锁的机制实现的,持久性通过 Redo Log(重做日志)来实现,原子性和一致性通过 Undo Log 来实现。
Undo Log 的原理很简单,为了满足事务的原子性,在操作任何数据之前,首先将数据备份到一个地方(这个存储数据备份的地方称为 Undo Log)。然后进行数据的修改。
如果出现了错误或者用户执行了 Rollback 语句,系统可以利用 Undo Log 中的备份将数据恢复到事务开始之前的状态。
和 Undo Log 相反,Redo Log 记录的是新数据的备份。在事务提交前,只要将 Redo Log 持久化即可,不需要将数据持久化。
当系统崩溃时,虽然数据没有持久化,但是 Redo Log 已经持久化。系统可以根据 Redo Log 的内容,将所有数据恢复到***的状态。对具体实现过程有兴趣的同学可以去自行搜索扩展。

Spring默认情况下会对运行期例外(RunTimeException),即uncheck异常,进行事务回滚。

如果遇到checked异常就不回滚。如何改变默认规则:

1 让checked例外也回滚:在整个方法前加上 @Transactional(rollbackFor=Exception.class)

2 让unchecked例外不回滚: @Transactional(notRollbackFor=RunTimeException.class)

3 不需要事务管理的(只查询的)方法:@Transactional(propagation=Propagation.not_supported)

上面三种方式也可在xml配置

 

ServiceA {           
     void methodA() {  
         ServiceB.methodB();  
     }  
}      
ServiceB {           
     void methodB() {  
     }           
}  
 

PROPAGATION_REQUIRED

假如当前正要执行的事务不在另外一个事务里,那么就起一个新的事务 
比如说,methodB的事务级别定义为PROPAGATION_REQUIRED, 那么由于执行methodA的时候
  1、如果methodA已经起了事务,这时调用methodB,methodB看到自己已经运行在methodA的事务内部,就不再起新的事务。这时只有外部事务并且他们是共用的,所以这时methodA或者methodB无论哪个发生异常methodA和methodB作为一个整体都将一起回滚。
  2、如果methodA没有事务,methodB就会为自己分配一个事务。这样,在methodA中是没有事务控制的。只是在methodB内的任何地方出现异常,methodB将会被回滚,不会引起methodA的回滚。

 

PROPAGATION_REQUIRES_NEW


启动一个新的, 不依赖于环境的 "内部" 事务. 这个事务将被完全 commited 或 rolled back 而不依赖于外部事务, 它拥有自己的隔离范围, 自己的锁, 等等. 当内部事务开始执行时, 外部事务将被挂起, 内务事务结束时, 外部事务将继续执行。
 比如我们设计methodA的事务级别为PROPAGATION_REQUIRED,methodB的事务级别为PROPAGATION_REQUIRES_NEW,那么当执行到methodB的时候,methodA所在的事务就会挂起,methodB会起一个新的事务,等待methodB的事务完成以后,他才继续执行。他与PROPAGATION_REQUIRED 的事务区别在于事务的回滚程度了。因为methodB是新起一个事务,那么就是存在两个不同的事务。
1、如果methodB已经提交,那么methodA失败回滚,methodB是不会回滚的。
2、如果methodB失败回滚,如果他抛出的异常被methodA的try..catch捕获并处理,methodA事务仍然可能提交;如果他抛出的异常未被methodA捕获处理,methodA事务将回滚。
 

PROPAGATION_NOT_SUPPORTED


当前不支持事务。比如methodA的事务级别是PROPAGATION_REQUIRED ,而methodB的事务级别是PROPAGATION_NOT_SUPPORTED ,那么当执行到methodB时,methodA的事务挂起,而他以非事务的状态运行完,再继续methodA的事务。


PROPAGATION_NEVER


不能在事务中运行。假设methodA的事务级别是PROPAGATION_REQUIRED, 而methodB的事务级别是PROPAGATION_NEVER ,那么methodB就要抛出异常了。 


PROPAGATION_NESTED


开始一个 "嵌套的" 事务,  它是已经存在事务的一个真正的子事务. 潜套事务开始执行时,  它将取得一个 savepoint. 如果这个嵌套事务失败, 我们将回滚到此 savepoint. 潜套事务是外部事务的一部分, 只有外部事务结束后它才会被提交. 

比如我们设计methodA的事务级别为PROPAGATION_REQUIRED,methodB的事务级别为PROPAGATION_NESTED,那么当执行到methodB的时候,methodA所在的事务就会挂起,methodB会起一个新的子事务并设置savepoint,等待methodB的事务完成以后,他才继续执行。。因为methodB是外部事务的子事务,那么
1、如果methodB已经提交,那么methodA失败回滚,methodB也将回滚。
2、如果methodB失败回滚,如果他抛出的异常被methodA的try..catch捕获并处理,methodA事务仍然可能提交;如果他抛出的异常未被methodA捕获处理,methodA事务将回滚。
 

 


 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值