事务的隔离级别

/ MYSQL / 1 条评论 / 559浏览 / 自动同步于GITHUB

事务的ACID特性

  1. 原子性
  2. 一致性(事务处理前后从一个一致性状态变换到另一个一致性状态)
  3. 隔离性(多个并发事务间的隔离)
  4. 持久性

无隔离处理下的几种问题

1. 脏读

并发的其中一个事务读取另一个事务未提交的内容,当另一个事务回滚后发现读的是无效数据

2. 不可重复读

并发的其中一个事务在一开始读取了一次数据,并在另一个事务提交后又读取了一次数据,发现两次读取的数据不一致

3. 幻读(虚读)

并发的其中一条事务对表内的所有行执行字段a的值从1变为2,这时在另一条事务中在表内添加了另一条a的值为1的数据,前一条事务会发现执行完后,表内仍有a字段值为1的记录

事务隔离级别

针对上述问题,INNODB设置了四种事务的隔离级别,由用户根据业务选择使用哪种隔离级别 ,在MySQL中默认是Repeatable Read级别,Oracle中默认是Read Committed级别。

事务隔离的实现原理:Mysql行数据上除了行数据值外还记录有数据修订版本号标记,同样的事务本身也存在有版本号标记,事务的版本号取决于事务内执行的第一个SQL操作(注意:不是Begin语句)。事务内对数据库行记录的修改会导致多个版本的数据存在于数据库内,即使事务提交老版本的数据也不会被立即删除,直至Mysql内不存在低于该版本的事务。在某些隔离级别的事务内,不能看到该事务版本之后提交的数据。如有事务1、2:

事务1                事务2
begin               begin
insert table1
                    select table2     确定该事务可见的版本号
commit              
                    select table1     查询不到事务1提交的数据

1. 读未提交(READ UNCOMMITTED)

读未提交隔离级别的事务,可以读到其他事务内内存内,未提交的数据。

在该隔离级别下, 读记录时不会添加锁,修改记录时,会在该记录上加上排他锁,在该事务未提交前,其他事务对该记录的修改操作将被阻塞。

2. 读已提交(READ COMMITTED)

读已提交隔离级别的事务,只能读到其他事务已提交的数据。

在该隔离级别下,读记录时不会添加锁,修改记录时,会在该记录上加上排他锁,在该记录未提交前,其他事务对该记录的修改操作将被阻塞。

3. 可重复读(REPEATABLE READ)

可重复隔离级别,是在读已提交的基础上,增加一点,本条事务内,读同一份数据,以该事务内对该数据的备份为标准(即使在此期间其他事务提交了该数据的修改,如果该事务内有这条数据,则读取到的以该事务内数据为准)。

在该隔离级别下,读记录时不会添加锁,修改记录时,会在该记录上加上排他锁,在该记录未提交前,其他事务对该记录的修改操作将被阻塞。

4. 串行(SERIALIZABLE)

串行执行隔离级别,该隔离级别从自身的定义上就已经避免了出现脏读、不可重复读、幻读的情况,所以不需要关心是读已提交、读未提交还是可重复读。

在串行隔离级别下,读记录时会在该记录上加上意向排他锁(如果修改时查询条件不是主键或索引,锁则是在表级别上的),如果添加意向排他锁时,该记录已经存在锁,则会阻塞当前线程直到其他事务提交。多个意向排它锁之间不会造成阻塞,会记录串行排队情况,当有其他事务要在该记录上添加排他锁时,意向排它锁队列的第一个是否是同一个事务添加,如果不是,则会阻塞添加排他锁的事务。

在串行隔离级别下,修改记录时会在该记录上加上排他锁,如果该记录上已经存在意向排他锁,如果意向排它锁队列的第一个不是由该事务添加的,修改操作会被阻塞。

(实际上,在INNODB中,无论是否使用事务,修改操作都会添加排他锁,区别在于有事务存在时,直到事务提交时,锁才会被释放)

其他

查看当前事务隔离级别 SELECT @@TX_ISOLATION

设置当前事务隔离级别 SET SESSION TRANSACTION ISOLATION LEVEL read uncommitted / read committed / repeatable read / serializable

Spring中注解设置 @Transactional(isolation = Isolation.REPEATABLE_READ)

  1. 12345678