mysql事务隔离级别

mysql事务隔离级别有四类:Read uncommitted、read committed、repeatable read、serializable

了解四类隔离级别之前,先了解三种情况:脏读、不可重复读、幻读
脏读:一个事务读到另一个事务已经修改但尚未提交到数据库的操作
举例:
事务A修改账户为100-10=90,已经修改但是还没有提交到数据库,
与此同时,事务B读取账户金额为90。这本来没什么大不了的,因为a提交之后账户余额真正变成90,顶多算一次错误的查询操作,但是如果此时A异常回滚,金额变成100.此时B的90将是错误的数据。


不可重复读:一个事务存在多次读取,多次读取条件一致但是返回结果不同的情况
举例:A事务select了一系列操作,B事务insert了一个新的数据,此时A事务又执行了一条select操作,与之前操作相同,但是返回的list内容已经发生变化


幻读:一个事务存在read-update-write操作,与此同时另一个事务插入了满足事务1read条件的数据,但是没有被修改
举例:A事务读到一系列数据,准备开始修改。与此同时事务B插入了一条满肚A事务读入要求的数据,但是这条数据没有赶上A的修改

事务隔离界别

脏读

不可重复读

幻读

read uncommited

可能

可能

可能

read commited

不可能

可能

可能

repeatable read

不可能

不可能

可能(mysql的innodb引擎可以解决部分幻读问题)

serializable

不可能

不可能

不可能

注意:mysql的可重复读可以解决部分幻读问题(通过mvcc,但是无法彻底解决)。

当前读和快照读源于mysql的mvcc模型。多版本并发控制(Multi-Version Concurrency Control, MVCC)是MySQL中基于乐观锁理论实现隔离级别的方式,用于实现读已提交和可重复读取隔离级别的实现。他是通过维护版本号实现的。
默认的select语句 是按照快照读查询的,这种查询无法避免幻读。
要想使用幻读要使用select … lock in shard mode 这种方式加锁解决。注意加锁。

mysql锁原理

mysql主要分为两类锁(一些特殊锁不做介绍):表锁、行锁
区别: 行锁锁住行,粒度小,开销大,并发度高
表锁锁住表,粒度大,开销小,并发度低
因此,表锁可以轻松解决幻读问题,因为只要有一个事务没结束,其他所有事务都会被阻塞

行锁主要有共享锁(加了共享锁的行,只可以读不可以删改)、排他锁(加了排他锁的行不能再加其他任何的锁)

mysql中select语句默认不会增加任何锁,update、insert、delete语句会加排他锁。因此执行update、insert、delete语句时,是可以select的。select可以使用select… for update为select操作加上排他锁,使用select … lock in share mode为select操作加上共享锁。当然,采用这两种方式的select将会和update、delete、insert发生阻塞。这也就解释了前面,使用select … lock in share mode会加上共享锁,导致另一个事务无法delete前面事务加锁的行,解决了部分当前读下的幻读问题。
如何解决幻读

很明显可重复读的隔离级别没有办法彻底的解决幻读的问题,如果我们的项目中需要解决幻读的话也有两个办法:

1、使用串行化读的隔离级别
2、MVCC+next-key locks:next-key locks由record locks(索引加锁) 和 gap locks(间隙锁,每次锁住的不光是需要使用的数据,还会锁住这些数据附近的数据)