事务的传播行为
当事务方法被另一个事务方法调用时,必须指定事务应该如何传播。比如,方法可能在现有的事务中运行,也可能开启一个新事务,并在自己的事务中运行。
事务的传播行为可以有事务的传播属性来指定,Spring定义了七种类传播行为;
- REQUIRED:如果有事务在运行,当前的方法就在这个事务中运行,否则,就开启一个事务,并在自己的事务中运行;
- REQUIRES_NEW:当前的方法必须开启新事务,并在自己的事务中运行,如果已经有事务在运行,必须将其挂起;
- SUPPORTS:如果有事务正在运行,当前方法可以在其中运行,但是如果没有事务在运行,它也可以不用运行在事务中;
- NOT_SUPPORTED:当前的方法不能运行在事务中,如果当前有事务在运行,就将它挂起;
- MANDATORY:当前的方法必须运行在事务中,如果没有运行的事务,就抛出异常;
- NEVER:当前的方法不应该运行在事务中,如果有运行的事务,就抛出异常;
- NESTED:如果有事务在运行,当前的方法就在他的嵌套事务中运行,否则,就启动一个新的事务,并在它自己的事务中运行;
事务的传播属性可以在@Transactional注解的propagation属性中定义。
数据库事务的并发问题
假设现在有两个事务并发执行,Transaction01和Transaction02;
1.脏读:某个事务读取了其他事务更新但未提交的数据,这种时候容易发生;
(1)Transaction01将某条记录的数值从20更新为30,但是并没有提交;
(2)这时Transaction02读取了Transaction01更新后的值30;
(3)但是Transaction01由于出现异常,将数据回滚回了数值20;
(4)这种状况下Transaction02读取的数值30就是一个脏的数据
2.不可重复读:
(1)Transaction01第一次读取某个数值时是20;
(2)Transaction02这时也读取了该数值,并且将数值更新为30;
(3)Transaction01第二次在读取该值时,发现该值是30,跟第一次读取的值不一样了,这就叫不可重复读;
3.幻读:
(1)Transaction01刚从表中读取了一部分数据;
(2)Transaction02这时向表中插入了一些数据;
(3)Transaction01再次读取时突然发现多了好多数据,就像出现了幻觉一样,这种就叫幻读;
为了解决事务的并发问题,我们就需要去设置事务的隔离级别。
数据库系统必须具有隔离并发运行各个事务的能力,使他们不会相互影响,避免各种并发问题,一个事务与其他事务隔离的程度被称为隔离级别。
- 读未提交(read uncommitted):允许事务读取其他事务未提交已修改的数据;
- 读已提交(read committed):事务只能读取其他事务提交之后的数据;这种状况解决了脏读的问题;
- 可重复读(repeatable read):确保Transaction01可以多次从一个字段中读取到相同的值,即Transaction01执行期间禁止其他事务对该记录做修改;这种状况解决了脏读,不可重复读的问题;
- 串行化(serializable):确保Transaction01可以多次从一个表中读取到相同的行,即在Transaction01执行期间,禁止其他事务对整个表进行添加,更新,删除的操作,可以避免任何的并发问题,但是性能比较差;这种状况解决了脏读,不可重复读,幻读的问题;
事务的传播属性可以在@Transactional注解的isolation属性中定义。