spring 事务——一篇文章搞定谜团
本文整理自:腾讯教育-图灵学院昭君老师视频
事务特性(4种):
原子性 (atomicity):强调事务的不可分割.
一致性 (consistency):事务的执行的前后数据的完整性保持一致.
隔离性 (isolation):一个事务执行的过程中,不应该受到其他事务的干扰
持久性(durability) :事务一旦结束,数据就持久到数据库
涉及的3个接口:
因数据库隔离级别不同出现的安全性问题:
1.脏读 :一个事务读到了另一个事务的未提交的数据
2.不可重复读 :一个事务读到了另一个事务已经提交的 update 的数据导致多次查询结果不一致.
3.虚幻读 :一个事务读到了另一个事务已经提交的 insert 的数据导致多次查询结果不一致.
为了解决这三种安全性问题引入了几种事务隔离级别:
解决读问题: 设置事务隔离级别(5种)
DEFAULT 这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别.
未提交读(read uncommited) :脏读,不可重复读,虚读都有可能发生
已提交读 (read commited):避免脏读。但是不可重复读和虚读有可能发生
可重复读 (repeatable read) :避免脏读和不可重复读.但是虚读有可能发生.
串行化的 (serializable) :避免以上所有读问题.
Mysql 默认:可重复读 repeatable read
Oracle 默认:读已提交read commited
如果出现事务嵌套,那么久设计事务的传播行为:
第一组:
PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
第二组:
PROPAGATION_REQUIRES_NEW 如果有事务存在,挂起当前事务,创建一个新的事务
第三组:
PROPAGATION_NOT_SUPPORTED 以非事务方式运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务方式运行,如果有事务存在,抛出异常
PROPAGATION_NESTED 如果当前事务存在,则嵌套事务执行
实践
测试事务:
案例1:A 有事务、B也有事务,然后A 事务中调用B 方法,都使用默认的传播行为,不去手动设置
首先要明白一个问题:
spring事务的 默认传播行为是PROPAGATION_REQUIRED 支持当前事务,如果不存在 就新建一个(默认)
结论:使用spring 默认的事务传播行为 A 中 调用 B 方法,B中的事务会加入当前事务,只产生一个事务
案例2:将案例1 中的 B方法的事务改为PROPAGATION_REQUIRES_NEW
结论:根据日志显示 出现挂起,新建的现象也就是2个事务。
源码:
针对下面4种情况分别讨论:
第一种 不做处理
案例3:B方法中 仍然使用新建,但是在方法最后抛出一个未处理的异常
结论:A、B 都进行了回滚
原因分析:
第二种:B抛出异常由A内部处理
结论:B回滚、A继续提交
第三种:如果将第二种的 B 方法的 事务行为改成PROPAGATION_REQUIRES 会怎么样
第4种情况:
结果:A、B都提交,不回滚
第五种 情况:
结论:B 回滚、A提交
第六种:如果异常是发生A方法中 回事怎么样呢???
开始验证:
结论:都回滚
第七种:
如果B事务改成PROPAGATION_REQUIRES_NEW,B运行无异常,但是A出现异常会是什么情况??
结论:A新建事务, 挂起当前、B创建一个新事务提交、此时A 方法异常 A回滚、但B不回滚