数据库锁

2019/02/16 数据库

数据库锁

1.InnoDB锁类型

1.1 S or X

在InnoDB中实现了两个标准的行级锁,可以简单的看为两个读写锁:

​ S-共享锁:又叫读锁,其他事务可以继续加共享锁,但是不能继续加排他锁;

​ X-排他锁:又叫写锁,一旦加了写锁后,其他事务就不能加锁了。

1.2 意向锁

在InnoDB中是表级锁,用来表达一个事务想要获取什么,意向锁分为:

​ 意向共享锁(IS锁):表达一个事务想要获取一张表中某几行的共享锁,一个事务在获取S锁之前,一定会先在所在表上加IS锁;

​ 意向排他锁(IX锁):表达一个事务想要获取一张表中某几行的排他锁,一个事务在获取X锁之前,一定会先在所在表上加IX锁。

如果没有这个锁,想要给这个表加上锁,一般的做法是去遍历每一行看看是否有行锁,这样的话效率太低,而我们有意向锁,只需要判断是否有意向锁即可,不需要再去一行行的扫描。

1.3 自增长锁

是一种特殊的表锁机制,提升并发插入性能。有几个特点:

​ 在sql执行完就释放锁,并不是事务执行完;

​ 对于insert…select大数据量插入会影响插入性能,因为会阻塞另外一个事务执行;

​ 自增算法可以配置。

可以根据不同的模式来进行调整自增长锁,有三种默认:传统模式,连续模式,交错模式:

​ 传统模式:就是默认的表锁;

​ 连续模式:对于插入的时候可以确定行数的适用互斥量,对于不能确定行数的适用表锁模式;

​ 交错模式:所有的都适用互斥量,有可能在批量插入时自增值不是连续的。一般来说如果不看重自增值连续就选择这个模式,性能最好。

2.InnoDB锁算法

2.1 记录锁/行锁(Record Locks)

记录锁是锁住记录的,锁住的是索引记录,并不是真正的数据记录。锁是加在索引上而不是行上的,Innodb一定存在聚簇索引,因此行锁最终都会落到聚簇索引上

  • 如果锁的是非主键索引,会在自己的索引上面加锁之后,然后再去主键上面加锁锁住;
  • 如果表上没有索引(包含没有主键),则会使用隐藏的主键索引进行加锁;
  • 如果要锁的列没有索引,则会进行全表记录加锁。

2.2 间隙锁(Gap Locks)

锁间隙,不锁记录,是对索引的间隙加锁。锁间隙的意思就是锁定某一个范围,其不会阻塞其他的gap锁,但是会阻塞插入间隙锁,防止幻读的关键。在RC隔离级别下,不会使用间隙锁,当然也包括RU;隔离级别为RR和Serializable时,就会存在间隙锁。

2.3 next-key锁

本质是记录锁加上gap锁,在RR隔离级别下(InnoDB默认),InnoDB对于行的扫描锁定都是使用该算法,但是如果查询扫描中有唯一索引会退化成只使用记录锁。因为唯一索引能确定行数,而其他索引不能确定行数,在其他事务中再次添加这个索引的数据有可能会造成幻读。

2.4 插入意向锁

插入数据的时候产生,在多个事务同时写入数据至同一个索引间隙的时候,并不需要等待其他事务完成,不会发生锁等待。假设有一个记录索引包含值4和7,不同的事务分别插入5和6,每个事务都会产生一个加在4-7之间的插入意向锁,获取在插入行上的排他锁,但是不会被互相锁住,因为数据行并不冲突。

如果有间隙锁了,插入意向锁会被阻塞!

3.MVCC

多版本并发控制技术,在InnoDB中,在每一行记录的后面增加两个隐藏列,记录创建版本号和删除版本号。通过版本号和行锁,从而提高数据库系统并发性能。

在MVCC中,对于读操作可以分为两种:

  • 快照读:读取历史数据,简单的select语句,不加锁,MVCC实现可重复读,使用的是MVCC机制读取undo中的已经提交的数据。所以它的读取是非阻塞的。
  • 当前读:需要加锁的语句,update,insert,delete,select…for update等等都是当前读。

在RR隔离级别下的快照读,不是以begin事务开始的时间作为snapshot建立时间点,而是以第一条select语句的时间点作为snapshot建立的时间点。以后的select都会读取当前时间点的快照值。

在RC隔离级别下每次快照读均会创建新的快照。

参考:

史上最全的select加锁分析

Search

    Table of Contents