3.锁

mysql加锁相关知识: https://www.cnblogs.com/crazylqy/p/7611069.html

Mysql锁系统总结:https://www.infoq.cn/article/ZAu0eWzsdTX9zoFr6C8W

1.锁

1.1.分类

  1. 按照锁数据的粒度
    1. 表锁。
    2. 行锁。隔离级别RR、RC,update、delete等语句命中索引时加上的锁都是行锁。只有LOCK TABLE …READ和LOCK TABLE … WRITE才能申请表级别的锁。
    3. 页锁。
  2. 按照锁的类型
    1. 共享锁(S锁):假设事务T1对数据A加上共享锁,那么事务T2可以读数据A,不能修改数据A。
    2. 排它锁(X锁):假设事务T1对数据A加上共享锁,那么事务T2不能读数据A,不能修改数据A。
  3. 按照状态
    1. 意向共享锁(IS锁):一个事务在获取(任何一行/或者全表)S锁之前,一定会先在所在的表上加IS锁。
    2. 意向排它锁(IX锁):一个事务在获取(任何一行/或者全表)X锁之前,一定会先在所在的表上加IX锁。
  4. 特殊
    1. 主键锁:自增的时候触发:锁[maxId, 正无穷)。
    2. 间隙锁,范围查询时,锁定一个范围。比如 id > 10,锁定范围 (10,无穷],即使没有数据。

1.2.为什么需要锁

锁机制用于管理对共享资源的并发访问,是对数据库的一种保护机制,也是数据库在事务操作中保证事务数据一致性和完整性的一种机制。

2.间隙锁

Mysql间隙锁是什么?主要用来解决什么问题的?

https://blog.csdn.net/sinat_27143551/article/details/81736330

Mysql隔离级别是可重复读,主要是用来解决幻读的问题(当然隔离级别为串行化的时候也可以,就是效率太低了)

死锁:MySQL在RR隔离级别下,间隙锁是默认开启,可能导致死锁。原因如下:

  1. 间隙锁范围交叉。间隙锁的范围交叉,会导致死锁。
  2. 间隙锁与插入意向锁冲突。
    1. 插入操作会先获取插入意向锁(Insert Intention Lock),而插入意向锁与已有的间隙锁互斥:
    2. 事务A锁定区间 (5, 10)(例如 DELETE FROM t WHERE id=7)。
    3. 事务B尝试插入 id=8,需要获取 (5, 10) 的插入意向锁,但被事务A的间隙锁阻塞。
    4. 事务A尝试插入 id=8(例如回滚后重新插入),需要获取自己的间隙锁,但此时事务B已在等待队列中。
    5. 结果:事务A等待事务B释放插入意向锁,事务B等待事务A释放间隙锁,触发死锁。

3.常见问题

MySQL,在数据库隔离级别是RR是,update table set b = ? where a = ?, 在a字段分别是主键、普通索引,唯一索引,没有索引的时候MySQL是什么加锁的?

主键 行锁, mysql 的 innodb的行锁加在主键索引上。

普通索引 间隙锁+行锁,也就是next key lock。

唯一索引 行锁

没有索引 锁全表

使用数据库能实现类型分布式锁的效果吗?

https://www.cnblogs.com/wintersoft/p/10787474.html

  1. 新增数据的场景:使用insert ignore实现,例如分布式定时任务执行任务。
  2. 砍价的业务逻辑中。
-- 1.使用悲观锁
BEGIN; -- 开始事务,必须增加需要变化的数据为查询条件,例如库存,用于进行双重校验
SELECT * FROM table_name WHERE id = 10 and num=10 FOR UPDATE; 
--  加的是行锁,并发时别的线程的SQL是阻塞的,高并发时会出现lock timeout。
COMMIT; -- 事务完成

-- 2.乐观锁
第一步:在t_share中增加一个砍价次数的字段,可以作为版本号
第二步:
BEGIN; -- 开始事务
Update table_name set num = 1 where id=10 and num=0; -- 通过修改的行数判断是否成功
COMMIT; -- 事务完成

事务锁超时(5.7): Lock wait timeout exceeded; try restarting transaction

https://blog.csdn.net/java__project/article/details/100137526

设置锁的超时时间(5.7)

https://blog.csdn.net/qq_37168856/article/details/105094465

4.死锁

发生死锁的场景?

  1. 批量更新数据间隙锁导致(修改当前事务的隔离级别);间隙锁和插入意向锁冲突。插入意向锁更像是队列需要前面的执行完才能轮到下一个事务执行。
  2. 行锁之间死锁(修改逻辑)。 事务A持有X1锁,申请X2锁。 事务B持有X2锁,申请X1锁。 两个事务死锁。

如何避免

  1. 降低隔离级别。RR隔离级别下,InnoDB会使用间隙锁防止幻读,但也增加了死锁风险。若无严格幻读要求,可以降为RC。
  2. 合理设计索引。避免索引覆盖范围过大
  3. 统一数据访问顺序。比较难
  4. 设置事务等待锁的超时时间,开启主动死锁检测。
  5. 谨慎使用SELECT … FOR UPDATE。使用乐观锁替代悲观锁

文章信息

张雪随笔
master
Homepage
Issues
Download

This Software is under the terms of The Unlicense.