likes
comments
collection
share

事务隔离级别和Spring传播行为,看了必会!

作者站长头像
站长
· 阅读数 7

事务概念

数据库操作的最小工作单元,为达到某个目的而执行的一系列操作,要么一起成功(事务提交),要么一起失败(事务回滚)。

四大特性ACID

  • Atomicity(原子性):一个事务中的所有操作,要么全部完成,要么全部不完成,不会结束在中间某个环节。事务在执行过程中发生错误,会被恢复到事务开始前的状态,就像这个事务从来没有执行过一样。

  • Consistency(一致性):在事务开始之前和事务结束以后,数据库的完整性没有被破坏。这表示写入的资料必须完全符合所有的预设规则,这包含资料的精确度、串联性以及后续数据库可以自发性地完成预定的工作。

    • 比如两个人进行转账,两个的总金额是1000,不过他们进行了多少次转账(事务),两个人的总额1000是不变的,这就是一致性状态;
  • Isolation(隔离性):数据库允许多个并发事务同时对其数据进行读写和修改的能力,隔离性可以防止多个事务并发执行时由于交叉执行而导致数据的不一致。

    • 事务隔离分为不同级别,包括读未提交(Read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(Serializable)。
  • Durability(持久性):事务处理结束后,对数据的修改就是永久的,即便系统故障也不会丢失。

四个隔离级别

事务之间相互影响的程度。

读未提交(Read Uncommitted)

在该隔离级别,所有事务都可以看到其它事务未提交的执行结果。事务可读取其它事务未提交的数据,会产生脏读

读已提交(Read Committed)

事务只能看见其它事务已经提交的结果数据。一个事务内多次查询同一数据返回不同的数据值,表示在查询间隔期间被其他事务修改并提交了,会产生不可重复读

可重复读 (repeatable Read)

保证同一事务的不同操作在并发读取的行数据是一样的。事务A读取某一范围的数据期间,事务B对该范围执行新增操作,导致事务A读取数据不一致,会产生所谓的幻读,Innodb通过版本控制解决了这一问题。

序列化(Serializable)

隔离的最高级别,通过强制让事务有序执行,解决幻读等问题。事务执行期间,对每个数据行加了共享锁,可能会引起其它事务查询超时等现象。

补充:

  1. 事务丢失

    • 回滚丢失 :事务AB同时操作一数据,B在A之前先提交,A事务回滚导致B事务的操作丢失。
    • 提交覆盖丢失:事务AB同时操作一数据,B在A之前先提交,A事务提交后覆盖了B事务的操作。
  2. 默认隔离级别:SQL server 、Oracle默认隔离级别是 RC,而MySQL默认的隔离级别是 RR。

你知道为什么Oracle选择RC作为默认级别,而MySQL要选择RR作为默认的隔离级别吗?为什么MySQL选择Repeatable Read作为默认隔离级别?

Spring事务传播行为

声明:以下内容有参考这位大佬的讲解 Spring事务传播行为详解 ,我只总结了结论,详细请看大佬链接。

千万别用百度了,真的浪费时间,谷歌真香!

Spring在TransactionDefinition接口中定义了七个事务传播行为,事务传播行为是Spring框架独有的事务增强特性,它和事务实际提供方<数据库>没什么关系。

什么是事务传播行为?

描述由某一个事务传播行为修饰的方法被嵌套进另一个方法时,事务如何传播。

代码中methodA() 方法嵌套调用了methodB() 方法,methodB() 的事务传播行为由 @Transaction(Propagation=XXX) 设置决定。这里需要注意的是methodA() 并没有开启事务,某一个事务传播行为修饰的方法并不是必须要在开启事务的外围方法中调用。

    private void methodA(){
        //业务逻辑代码
        methodB();
    }
    @Transactional(Propagation=XXX)
    private void methodB() {
        //业务逻辑代码
    }

事务隔离级别和Spring传播行为,看了必会!

PROPAGATION_REQUIRED默认 必须有事务

  • 外围方法未开启事务的情况下Propagation.REQUIRED修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
  • 外围方法开启事务的情况下Propagation.REQUIRED修饰的内部方法会加入到外围方法的事务中,所有Propagation.REQUIRED修饰的内部方法和外围方法均属于同一事务,只要一个方法回滚,整个事务均回滚。

PROPAGATION_SUPPORTS可有可无

  • 外围方法未开启事务的情况下PROPAGATION_SUPPORTS修饰的内部方法不会开启自己的事务。
  • 外围方法开启事务的情况下PROPAGATION_SUPPORTS修饰的内部方法会加入到外围方法的事务中。

PROPAGATION_MANDATORY必须有事务

  • 这个容易理解,就是外围方法必须有事务,内部方法都加入到外围方法的事务中。如果外围方法没有事务就抛出异常。

PROPAGATION_REQUIRES_NEW必须有事务

  • 外围方法未开启事务的情况下Propagation.REQUIRES_NEW修饰的内部方法会新开启自己的事务,且开启的事务相互独立,互不干扰。
  • 外围方法开启事务的情况下Propagation.REQUIRES_NEW修饰的内部方法依然会单独开启独立事务,且与外部方法事务也独立,内部方法之间、内部方法和外部方法事务均相互独立,互不干扰。

PROPAGATION_NOT_SUPPORTED不需要事务

  • 外围方法未开启事务的情况下PROPAGATION_NOT_SUPPORTED修饰的内部方法不会开启自己的事务。
  • 外围方法开启事务的情况下PROPAGATION_NOT_SUPPORTED修饰的内部方法会将外围方法的事务挂起后执行,不会开启自己的事务,运行完后再继续外围方法的事务。

PROPAGATION_NEVER不需要事务

  • 外围方法未开启事务的情况下PROPAGATION_NEVER修饰的内部方法不会开启自己的事务。
  • 外围方法开启事务的情况下PROPAGATION_NEVER修饰的内部方法会抛出异常。

PROPAGATION_NESTED必须有事务

  • 外围方法未开启事务的情况下Propagation.NESTED和Propagation.REQUIRED作用相同,修饰的内部方法都会新开启自己的事务,且开启的事务相互独立,互不干扰。
  • 外围方法开启事务的情况下Propagation.NESTED修饰的内部方法属于外部事务的子事务,外围主事务回滚,子事务一定回滚,而内部子事务可以单独回滚而不影响外围主事务和其他子事务。