mysql

InnoDB隔离级别实现

2019-02-27  本文已影响8人  骁兵

一致性读(MVCC,无锁读)

  InnoDB使用数据库某一个时间点的快照提供给查询,查询只能看到该时间点之前已提交的数据 或者 当前查询事务自己做的修改。
  在可重读和读已提交的普通select语句都是一致性读,一致性读不会在表上设置任何锁。

快照不适用于DML语句
  快照只应用于select语句,而不应用在DML语句(insert、update、delete),如果你在一个事务中插入或修改某些行,并提交事务,另一个同时运行的可重复读事务,如果执行delete或update语句,会影响第一个事务提交的数据,即使第二个事务的查询并看不到第一个事务的修改,并且第二个事务做出修改之后,它就可以查询到这些第一个事务做的修改。如以下栗子:
特殊select语句

  对于特殊的select语句,INSERT INTO ... SELECT, UPDATE ... (SELECT),和CREATE TABLE ... SELECT,如果是非序列化的其他隔离级别,则以读已提交的隔离级别来执行一致性读。

两种锁定读

  如果使用普通的select语句(无锁),然后再执行更新操作(CAS),可能会出现问题,因为别的事务也可以同时修改你查出来的数据。InnoDB提供了两种锁定读,两种锁都在事务结束之后释放:
  SELECT ... FOR SHARE:对读取的数据加共享锁,之后其他事务不能对其修改,如果读取之前,别的事务已经对数据做了修改,查询会等待其他事务锁的释放
  SELECT ... FOR UPDATE:跟update语句一样,其他事务无法再对数据加锁。一致性读会忽略这些锁,照样读取数据而不需要等待锁释放,因为老版本数据并不能加锁,它们是通过undo logs重建出来的存放在内存的记录拷贝。

  以下语句,外部查询的for update不会对内部select的查询加锁,除非对内部的select加for udpate。

  用在for update和for share上两种拒绝等待锁的方式:

可重复读

  1. 一致性非锁定读(普通select)
  1. 锁定读(for update或for share)、update、delete

读已提交

  1. 一致性非锁定读(普通select)
  1. 锁定读(for update或for share)、update、delete

举个栗子

  以上表没有索引,所以执行以下语句(事务A)时,搜索会走隐藏的聚簇索引,首先它会申请一个所有行的排它锁,然后再判断是否需要锁定这些行,如果InnoDB判断不需要修改该行,它会释放该行的锁,否则它会持有该锁,直到事务结束。(如果使用默认的可重复读级别,update语句会申请一个所有行的排它锁,并且不会释放锁,直到事务结束。)
  事务B执行时,需要等待事务A释放锁
  如果where条件使用了索引,则事务A只会锁住索引列
上一篇 下一篇

猜你喜欢

热点阅读