MySQL在默认事务下各SQL语句使用的锁分析

 数据库使用锁是为了支持更好的并发,提供数据的完整性和一致性。InnoDB是一个支持行锁的存储引擎,锁的类型有:共享锁(S)、排他锁(X)、意向共享(IS)、意向排他(IX)。为了提供更好的并发,InnoDB提供了非锁定读:不需要等待访问行上的锁释放,读取行的一个快照。该方法是通过InnoDB的一个特性:MVCC来实现的

InnoDB有三种行锁的算法:

1,Record Lock:单个行记录上的锁。

2,Gap Lock:间隙锁,锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。

3,Next-Key Lock:1+2,锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。

如果采用MySQL默认的事务隔离级别(可以重复读:repeatable read

可重复读取(Repeatable Read):防止(避免)不可重复读取和脏读,但是有时可能出现幻读数据。这可以通过“共享读锁”和“排他写锁”实现。读取数据的事务将会禁止写事务(但允许读事务),写事务则禁止任何其他事务。

  • 脏读:一个事务还未提交,另外一个事务访问此事务修改的数据,并使用,读取了事务中间状态数据。
  • 幻读:一个事务读取2次,得到的记录条数不一致,由于2次读取之间另外一个事务对数据进行了增删。
  • 不可重复读:一个事务读取同一条记录2次,得到的结果不一致,由于在2次读取之间另外一个事务对此行数据进行了修改。

1.SELECT ... FROM

  >是一个快照读,通过读取数据库的一个快照,不会加任何锁,除非将隔离级别设置成了 SERIALIZABLE 。

2.SELECT ... FROM ... LOCK IN SHARE MODE

>在所有索引扫描范围的索引记录上加上共享的next key锁;如果是唯一索引,只需要在相应记录上加index record lock。这些被共享lock住的行无法进行update/delete。
>允许其它事务对这些记录再加SHARE锁
>如果没有使用到索引,则锁住全表(表级的排他锁),无法进行insert/update/delete。

3.SELECT ... FROM ... FOR UPDATE

>在所有索引扫描范围的索引记录上加上排他的next key锁。如果是唯一索引,只需要在相应记录上加index record lock。
>如果没有利用到索引将锁住全表(表级的排他锁),其它事务无法进行insert/update/delete操作。

4. UPDATE ... WHERE ...

>在所有索引扫描范围的索引记录上加上排他的next key锁。如果是唯一索引,只需要在相应记录上加index record lock。
>如果没有利用到索引将锁住全表(表级的排他锁),其它事务无法进行其他的insert/update/delete操作。;

5. DELETE FROM ... WHERE ...

>语句在所有索引扫描范围的索引记录上加上排他的next key锁。如果是唯一索引,只需要在相应记录上加index record lock。
>如果没有利用到索引将锁住全表(表级的排他锁),其它事务无法进行其它的insert/update/delete操作。

6. INSERT

>在插入的记录上加一把排他锁,这个锁是一个index-record lock,并不是next-key 锁,因此就没有gap 锁,他将不会阻止其他会话在该条记录之前的gap插入记录。

 

总结:

隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也越大,鱼和熊掌不可兼得啊。对于多数应用程序,可以优先考虑把数据库系统的隔离级别设为Read Committed它能够避免脏读取,而且具有较好的并发性能。尽管它会导致不可重复读、幻读这些并发问题,在可能出现这类问题的个别场合,可以由应用程序采用悲观锁或乐观锁来控制。

posted @ 2018-09-07 12:02  FrankYou  阅读(2892)  评论(0编辑  收藏  举报