内容仅为个人理解,我也在不断的纠正自己的理解。
1 | -- 以下讨论都基于:Innodb,事务隔离机制采用RR |
First Of All,Mysql数据库在事务隔离级别为RR的情况下,如果要避免幻读,就要通过间隙锁。那么如何最简单的实现间隙锁,就是通过select语句中 for update 排他锁。正常的select语句是不会加锁的。而是通过访问记录的版本链的过程,实现MVCC(多版本并发控制),也可以简单的理解为快照读,并不加锁。在select for update, 还有 insert, update, delete 的时候,就需要考虑锁机制了。另外mysql的锁,锁定的是索引,并不是数据。
行锁算法(注意是算法哦)
普通行锁
唯一索引,且查询的记录存在
间隙锁
锁定一个范围,但不包括记录本身。GAP锁的目的,是为了防止同一事务的两次当前读,出现幻读的情况。
常见于,键值不存在条件范围内,叫做间隙(GAP),引擎会对该“间隙”加锁。
Next-key Lock(行锁&间隙锁)
相当于两种锁的结合。锁定一个范围,并且锁定记录本身。对于行的查询,都是采用该方法,主要目的是解决幻读的问题。
锁的类型:
共享锁(S)、排他锁(X)、意向共享(IS)、意向排他(IX)
行锁,表锁其实是锁的粒度的概念,共享锁和排它锁是具体的实现。
共享锁(S): 允许其他事务来读取,但是阻止其他事务,在该行获取该行的排它锁。简单的记忆:能读不能写。共享锁的查询举例: select … lock in share mode。
排它锁(X): 允许持有排它锁的事务读写数据,阻止其他事务获取该行的共享锁和排它锁。但是其他事务还是可以读的。(普通的select语句,并不影响数据查询)。
1 | -- 排它锁的举例: |
间隙锁之举例
前言:始终不要忘记间隙锁的目的,是为了解决幻读。所以开发工作中,要主动思考,规避在某些并发环境下,会出现幻读,常见做法便是:在sql中加入for update,或是乐观锁。在运维工作中,也要留意数据库,出现同样间隙锁的性能问题。(遇到过,数据库大量的insert 导致的间隙锁)