MySQL锁的分类
数据库有很多客户端访问,访问过程会出现同时处理同一张表、同一条数据的情况,处理的逻辑各不一致,为了保证数据最后的准确性,需要加锁,实现对资源的控制。数据库是这样,Java代码中的并发编程也是如此。
MySQL锁的分类
- 全局锁
- 表级别锁:表锁、元数据锁(MDL)、表意向锁、AUTO-INC 锁
- 行级别锁:Record Lock(记录锁)、Gap Lock(间隙锁)、Next-Key Lock(临键锁)、插入意向锁
全局锁
要使用全局锁,则要执行这条命令:
flush tables with read lock
执行后,整个数据库就处于只读状态了。应用:做全库逻辑备份。
表级别锁
表锁
//表级别的共享锁,也就是读锁;
lock tables t_student read;
//表级别的独占锁,也就是写锁;
lock tables t_stuent write;
unlock tables
元数据锁(MDL)
meta data lock MDL 是在事务提交后才会释放,这意味着事务执行期间,MDL 是一直持有的。
表意向锁
有了「意向锁」,由于在对记录加独占锁前,先会加上表级别的意向独占锁,那么在加「独占表锁」时,直接查该表是否有意向独占锁,如果有就意味着表里已经有记录被加了独占锁,这样就不用去遍历表里的记录。 所以,意向锁的目的是为了快速判断表里是否有记录被加锁。
AUTO-INC 锁
- 表里的主键通常都会设置成自增的,这是通过对主键字段声明 AUTO_INCREMENT 属性实现的。
- 可以在插入数据时,可以不指定主键的值,数据库会自动给主键赋值递增的值,这主要是通过 AUTO-INC 锁实现的。
- AUTO-INC 锁是特殊的表锁机制,锁不是再一个事务提交后才释放,而是再执行完插入语句后就会立即释放。
在插入数据时,会加一个表级别的 AUTO-INC 锁,然后为被 AUTO_INCREMENT 修饰的字段赋值递增的值,等插入语句执行完成后,才会把 AUTO-INC 锁释放掉。 一个事务在持有 AUTO-INC 锁的过程中,其他事务的如果要向该表插入语句都会被阻塞,从而保证插入数据时,被 AUTO_INCREMENT 修饰的字段的值是连续递增的。
优化
但是, AUTO-INC 锁再对大量数据进行插入的时候,会影响插入性能,因为另一个事务中的插入会被阻塞。因此, 在 MySQL 5.1.22 版本开始,InnoDB 存储引擎提供了一种轻量级的锁来实现自增。 一样也是在插入数据的时候,会为被 AUTO_INCREMENT 修饰的字段加上轻量级锁,然后给该字段赋值一个自增的值,就把这个轻量级锁释放了,而不需要等待整个插入语句执行完后才释放锁。
行级别锁
Record Lock(记录锁)
仅仅把一条记录锁上
Gap Lock(间隙锁)
- 锁定一个范围,但是不包含记录本身
- 只存在于可重复读隔离级别,目的是为了解决可重复读隔离级别下幻读的现象。
- 表中有一个范围 id 为(3,5)间隙锁,那么其他事务就无法插入 id = 4 这条记录了,这样就有效的防止幻读现象的发生。
- 隙锁之间是兼容的,即两个事务可以同时持有包含共同间隙范围的间隙锁,并不存在互斥关系,因为间隙锁的目的是防止插入幻影记录而提出的
Next-Key Lock(临键锁)
- Record Lock + Gap Lock 的组合,锁定一个范围,并且锁定记录本身。
- 是包含间隙锁+记录锁的,如果一个事务获取了 X 型的 next-key lock,那么另外一个事务在获取相同范围的 X 型的 next-key lock 时,是会被阻塞的。
插入意向锁
- 如果有的话,插入操作就会发生阻塞,直到拥有间隙锁的那个事务提交为止(释放间隙锁的时刻),在此期间会生成一个插入意向锁,表明有事务想在某个区间插入新记录,但是现在处于等待状态。
- 插入意向锁名字虽然有意向锁,但是它并不是意向锁,它是一种特殊的间隙锁,属于行级别锁。
- 间隙锁锁住的是一个区间,那么「插入意向锁」锁住的就是一个点。因而从这个角度来说,插入意向锁确实是一种特殊的间隙锁。