2020-11-18 02:11:47
行锁、表锁、间隙锁的使用场景与死锁排查方法如下:
一、三种锁的核心特性与使用场景行锁
特性:锁定特定数据行,粒度最细,并发性最高。InnoDB引擎默认使用,支持事务隔离级别中的行级控制。
使用场景:
高并发读写场景(如电商订单更新、用户信息修改)。
需要精确控制单行数据一致性的操作(如转账业务)。
示例:SELECT * FROM users WHERE id = 1 FOR UPDATE; -- 加行锁UPDATE users SET name = 'New Name' WHERE id = 1; -- 更新数据
表锁
特性:锁定整张表,粒度最粗,并发性最低。所有操作需排队执行。
使用场景:
批量数据操作(如全表更新、TRUNCATE TABLE)。
数据库维护任务(如备份、结构变更)。
示例:LOCK TABLES users WRITE; -- 加写锁-- ... 进行批量操作 ...UNLOCK TABLES; -- 释放锁
间隙锁
特性:锁定数据行之间的“间隙”,防止幻读(其他事务在间隙内插入数据)。常与行锁结合为next-key lock。
使用场景:
范围查询时保证数据一致性(如查询年龄在20-30岁之间的用户,防止其他事务插入25岁用户)。
唯一索引缺失时的重复值检查。
示例:表数据为(1, 2, 4),事务A查询WHERE id BETWEEN 2 AND 4时,间隙锁会阻止其他事务插入id=3的数据。
死锁成因
循环依赖:事务A持有锁L1并请求锁L2,同时事务B持有锁L2并请求锁L1。
锁粒度冲突:表锁与行锁混用,或间隙锁范围重叠。
长事务:事务持有锁时间过长,增加冲突概率。
排查步骤
查看数据库日志:
MySQL通过SHOW ENGINE INNODB STATUS命令获取最近死锁信息。
日志中包含死锁事务ID、锁定资源类型(行锁/表锁/间隙锁)、SQL语句等关键信息。
分析死锁图:
根据日志中的“WAIT-FOR GRAPH”定位循环依赖链。
示例:事务1等待行锁A,事务2等待行锁B,但事务1已持有B且事务2已持有A。
常见死锁场景
交叉更新:两个事务更新不同行,但后续操作交叉请求对方已锁定的行。
间隙锁冲突:两个事务在相同范围内插入数据,间隙锁互相阻塞。
表锁与行锁混用:事务A加表锁后尝试加行锁,事务B已持有行锁并请求表锁。
优化代码逻辑
减少锁持有时间:尽快提交事务,避免长时间占用锁。
统一锁顺序:所有事务按固定顺序获取锁(如先锁行A再锁行B)。
拆分长事务:将大事务拆分为多个小事务,降低冲突风险。
调整锁粒度
高并发场景优先使用行锁,避免表锁。
范围查询时合理设计索引,减少间隙锁范围。
数据库配置优化
调整innodb_lock_wait_timeout参数(默认50秒),缩短等待时间。
启用死锁检测(InnoDB默认开启),通过innodb_deadlock_detect=ON自动回滚较小事务。
重构数据库设计
避免热点数据集中,分散读写压力。
使用乐观锁(如版本号控制)替代悲观锁,减少锁竞争。