MySQL-锁
全局锁 FTWL
使用全局锁后数据库只允许读不允许写。
# 1.
FLUSH TABLE WITH READ LOCK; # 加锁
UNLOCK TABLES;# 解锁
# 2.
SET GLOBAL READ_ONLY=TRUE
# 第一种方式在客户端断开后会自动释放
表锁
MyISAM引擎只有表锁。
表锁分为两种 LOCK命令加锁和MDL锁
LOCK锁
通过LOCK命令加锁
LOCK TABLE user_job READ; # 本线程和其它线程只能读表
LOCK TABLE user_job WRITE; # 本线程可以读写,其它线程不能读写
UNLOCK user_job; 解锁
MDL锁
MDL锁 metadata lokc 即元数据锁,5.5之后引进的表级锁,保证读写正确性。
MDL锁不能手动添加,由MySQL自动添加:
- 对表作增删改查,加MDL读锁。
- 对表结果作变更操作时,加MDL写锁。
MDL锁会在事务提交后自动释放。
MDL读锁不互斥,可以对表加多个MDL读锁,读写锁之间互斥。
MDL锁是在Server层实现的。
行锁
- 行共享锁
Shared Lock 又叫做S锁。一条数据加了S锁之后,其它事务也可以读数据,共享一把锁。
select * from user_job where id = 1 LOCK IN SHARE MODE
- 行排他锁
Exclusive Lock,又称为写锁,X锁。一条数据加了X锁后,其它事务只能阻塞。
修改数据,insert, update,delete时MySQL自动加排它锁。
select * from user_job where id =1 for update
意向锁
InnoDB行锁和表锁是可以共存的,当加表锁的时候需要遍历每一行看是否有行锁,效率会降低。为解决这个问题引入了意向锁。
- 意向共享锁
Intention Shared Lock 意向共享锁 IS锁 - 意向排他锁
Intention Exclusive Lock 意向排它锁 IX锁
意向锁右MySQL自动维护:
- 当对行数据加S锁时,对整个表加IS锁
- 当对行数据加X锁时,对整个表加IX锁
当加表锁时执行检查是否有意向锁即可。
IX锁与X锁和S锁互斥,Is锁与X锁互斥,与S锁共享。
InnoDB如何解决幻读问题
通过行数来解决。锁住的时索引,没有索引时锁表。
辅助索引被锁后,对应主键索引也会被锁,InnoDB主键索引即数据。主键索引被锁整条数据都会被锁。
即便覆盖索引也会锁整条数据。
行锁有三种算法:记录锁,间隙锁和临键锁,MySQL就是通过临键锁解决幻读问题。
- 记录锁:Record Lock,即锁住一条数据
- 间隙锁: Gap Lock, 索引间隙上的锁。匹配记录的第一条的上一条到最后一条的后一条的中间,开区间。如当where 条件时范围时,整个范围都会被锁,这也造成不存在的记录也会被锁定。
- 临键锁:Next-Key Lock , 记录锁和间隙锁的结合。区间左开右闭,范围查询时,会锁住记录和间隙,InnoDB行锁的默认算法。
RR级别才会有临键锁,RC只有记录锁。
行锁的加锁规则
- MySQL默认是RR级别,使用临键锁
- 使用主键或唯一索引命中一条记录的时候会退化为记录锁。
- 没有命中记录会退化为间隙锁
- 查找过程访问到对象时才会加锁
- 索引上进行等值查询时,向右遍历发现最后一个值不满足条件的时候,临键锁会退化为间隙锁。
乐观锁和悲观锁
乐观锁:保持乐观的态度,认为不会修改数据,默认不上锁,在执行更新时才会判断别人是否也修改了数据,是则撤销操作,反之执行。
冲突比较少的时候, 使用乐观锁(没有悲观锁那样耗时的开销) 由于乐观锁的不上锁特性,所以在性能方面要比悲观锁好,比较适合用在DB的读大于写的业务场景。
悲观锁:悲观态度,认为会修改数据,先上锁再操作。
读取频繁使用乐观锁,写入频繁使用悲观锁。