MySQL脏读、不可重复读、幻读

事务的特性:【ACID】

  • 原子性【Atomicity】:指处于同一个事务中的多条语句是不可分割的,即一个事务内的所有语句,要么全部成功要么全部失败。
  • 一致性【Consistency】:事务必须使数据库从一个一致性状态变换到另外一个一致性状态。比如转账,转账前两个账户余额之和为2k,转账之后也应该是2K
  • 隔离性【Isolation】:指多线程环境下,一个线程中的事务不能被其他线程中的事务打扰
  • 持久性【Durability】:事务一旦提交,就应该被永久保存起来。

事务隔离性问题: 
如果不考虑事务的隔离性,会出现以下问题:

  • 脏读:指一个线程中的事务读取到了另外一个线程未commit或者回滚的数据。
  • 脏读官方定义:即一个事务中读取到另外一个事务未提交的数据。

 

  • 不可重复读:指一个线程中的事务读取到了另外一个线程中【提交】update的数据,导致两次读取到的数据内容不一致。
  • 不可重复读与脏读的区别是:脏读读到的是未提交的数据,而不可重复读读到的却是已经提交的数据,但是其违反了数据库事务一致性的要求。

  

  • 幻读:指一个线程中的事务读取到了另外一个线程中【提交】的 insert的数据,两次读取到的数据总量不一样。
  • 幻读官方定义:指在同一事务下,连续执行两次同样的SQL语句可能导致不同的结果,第二次的SQL语句可能会返回之前不存在的行。

隔离级别:

隔离级别

脏读(Dirty Read)

不可重复读(NonRepeatable Read)

幻读(Phantom Read)

未提交读(Read uncommitted)

可能

可能

可能

已提交读(Read committed)

不可能

可能

可能

可重复读(Repeatable read)

不可能

不可能

可能

可串行化(Serializable )

不可能

不可能

不可能

级别越高,数据越安全,但性能越低。


大致的区别在于

  脏读是读取另一个事务中未提交的数据,比如在事务B中执行update但是还没有commit,事务A可以读取这个数据并使用,即使事务B进行了数据回滚,A仍然使用这个脏数据。(只有在RU级别下才会产生此问题)

  不可重复读是由于另一个事务对数据的更改并提交所造成的两次读取不一致(MySQL官方将不可重复读的问题定义为Phantom Problem,即幻像问题)

  而幻读是由于另一个事务插入或删除引起的数量不一致,本质上幻读是一种特殊的不可重复读,特指行。

 

 RR级别,可重复读通过使用不同的快照读来实现

  • Mysql对于RR的隔离级别下,读取的是事务开始时的快照【详见MVCC多版本并发控制】,所以此时不存在不可重复读现象。即使其它事务修改了A记录,本事务内再次查询仍与第一次查询结果一样,都是本事务开启时产生的A记录的快照版本。【这里对的快照都是指:行数据】
  • 在RC隔离级别下是读取最新的快照,如果其他事务更新了该记录,那么两次查询结果就不一样

 

Next-key-locking是如何解决幻读问题的:

  在 RR(可重复读) 级别下,

    如果查询条件为等值查询,能使用上唯一索引,或者是主键,那么降级,仅加行锁即可,

    如果是一个范围查询,那么就会给这个范围加上 gap 锁或者 next-key锁 (行锁+gap锁)。

    如果是辅助索引,且为等值查询,那么会使用Next-key-locking,在该值,以及该值上下临近的范围内加锁。比如辅助索引的值为 1,3,6,10; 查询where=3,会用nexy-key-lock锁住(1,3],然后用Gap-lock锁住(3,6)【注释:这里辅助索引是离散的,nexy-key-lock锁住的范围也不包含 1 和 6,但是包含1到6之间的范围】

    如果是辅助索引且是范围查询,比如where > 6, 那么会锁住(6, +∞)这个范围,而不是10

结论:

  • next-key锁,是通过锁住查询范围,防止幻读的(防止其它事务向查询范围内插入或删除记录),也可以防止不可重复读,但RR级别下已经有了其他可重复读的实现方法。

 

 

  如还不理解,请看https://blog.csdn.net/qq_33591903/article/details/81672260

posted @ 2019-12-19 17:08  _Eternity味道  Views(1074)  Comments(0Edit  收藏  举报