MySql锁问题

一、InnoDB存储引擎的锁算法

1、Record lock

单个行记录上的锁,record locks 总是锁定索引记录,即使一个表并没有定义索引。这种情况下,InnoDB创建了一个隐藏的clustered索引,并用这个索引来进行record locking

2、 Gap lock

间隙锁,锁定一个范围,不包括记录本身

3、Next-key lock

record+gap 锁定一个范围,包含记录本身,是一个记录锁在索引记录上和一个区间锁在区间的组合,一个index的record lock和在这个index之前的间隙的gap lock的组合。Next-key locking 组合了 index-row locking 和 gap locking。

InnoDB在搜索或者扫描表索引时使用了行级锁定,他在遇到的索引记录上设置共享或排他锁。因此, 行级锁实际上是索引记录锁。

另外,一个索引上的next-key锁也会影响index记录之前的"gap", 那就是,一个 next-key锁是一个index-record lock 加上一个 gap lock, 它位于指定索引及索引之前的间隙, 形如 (a, b]。如果一次护花拥有一个记录行R的索引的共享或排他锁, 另外一个会话将不能插入新索引行到间隙之间。

二、Lock的精度和模式

1、分为 行锁、表锁、意向锁
2、模式分为
  • 锁的类型 ——【读锁和写锁】或者【共享锁和排他锁】即 【X or S】

  • 锁的范围 ——【record lock、gap lock、Next-key lock】

2、什么是意向锁

innodb的意向锁主要用做多粒度的锁并存的情况。

比如事务A要在一个表上加S锁,如果表中的一行已被事务B加了X锁,那么该锁的申请也应被阻塞。如果表中的数据很多,逐行检查锁标志的开销将很大,系统的性能将会受到影响。为了解决这个问题,可以在表级上引入新的锁类型来表示其所属行的加锁情况,这就引出了“意向锁”的概念。

举个例子,如果表中记录1亿,事务A把其中有几条记录上了行锁了,这时事务B需要给这个表加表级锁,如果没有意向锁的话,那就要去表中查找这一亿条记录是否上锁了。

如果存在意向锁,那么假如事务A在更新一条记录之前,先加意向锁,再加X锁,事务B先检查该表上是否存在意向锁,存在的意向锁是否与自己准备加的锁冲突,如果有冲突,则等待直到事务A释放,而无须逐条记录去检测。事务B更新表时,其实无须知道到底哪一行被锁了,它只要知道反正有一行被锁了就行了。

三、快照读和当前读

1、快照读(snapshot read)

简单的select操作

2、当前读(current read)
select ... lock in share mode
select ... for update
insert
update
delete

在RR级别下,快照读是通过MVVC(多版本控制)和undo log来实现的,当前读是通过加record lock(记录锁)和gap lock(间隙锁)来实现的。
所以从上面的显示来看,如果需要实时显示数据,还是需要通过加锁来实现。这个时候会使用next-key技术来实现。

在mysql中,提供了两种事务隔离技术,第一个是mvcc,第二个是next-key技术,这个在使用不同的语句的时候可以动态选择。不加lock inshare mode之类的就使用mvcc,否则使用next-key。mvcc的优势是不加锁,并发性高。缺点是不是实时数据。next-key的优势是获取实时数据,但是需要加锁。

三、总结

  1. innodb对于行的查询使用next-key lock

  2. Next-locking keying为了解决Phantom Problem幻读问题

  3. 当查询的索引含有唯一属性时,将next-key lock降级为record key

  4. Gap锁设计的目的是为了阻止多个事务将记录插入到同一范围内,而这会导致幻读问题的产生

  5. 有两种方式显式关闭gap锁:(除了外键约束和唯一性检查外,其余情况仅使用record lock) A. 将事务隔离级别设置为RC B. 将参数innodb_locks_unsafe_for_binlog设置为1

  6. innodb中的RR隔离级别是通过next-key locking是如何解决幻读问题的,就是锁住一个范围。

  7. 意向锁的主要作用是处理行锁和表锁之间的矛盾,能够显示“某个事务正在某一行上持有了锁,或者准备去持有锁”

Innodb的默认事务隔离级别是rr(可重复读)。它的实现技术是mvcc。基于版本的控制协议。该技术不仅可以保证innodb的可重复读,而且可以防止幻读。但是它防止的是快照读,也就是读取的数据虽然是一致的,但是数据是历史数据。

如何做到保证数据是一致的(也就是一个事务,其内部多次读取对应某一个数据的时候,数据都是一样的),同时读取的数据是最新的数据。innodb提供了一个间隙锁的技术,也就是结合grap锁与行锁,达到最终目的。当使用索引进行插入的时候,innodb会将当前的节点和上一个节点加锁。这样当进行select的时候,就不允许加x锁。那么在进行该事务的时候,读取的就是最新的数据。

参考
1、InnoDB Record, Gap, and Next-Key Locks
2、理解innodb的锁(record,gap,Next-Key lock)
3、详谈innodb的锁(record,gap,Next-Key lock)
4、Next-key locking是如何解决幻读问题的
5、使用next-key locks 用于搜索和索引扫描,可以防止幻读
6、innodb的记录锁、gap锁、next-key锁
7、当前读和快照读
8、Mysql的排他锁和共享锁
9、【MySQL】gap lock 浅析
10、MySQL中的锁(表锁、行锁,共享锁,排它锁,间隙锁)
11、MySQL 中隔离级别 RC 与 RR 的区别

你可能感兴趣的:(MySql锁问题)