数据库死锁场景如何复现和解决?
				
									
					
					
						|  | 
							freeflydom 2025年3月17日 10:32
								本文热度 1173 | 
					
				 
				需了解死锁先看这一篇
死锁是如何被发现和解决的?这篇文章告诉你
一、死锁的产生原因
- 死锁发生在两个或多个事务相互等待对方释放锁,导致它们都无法继续执行的情况,形成死锁。
- 这种情况在并发高的系统中比较常见,尤其是在多个事务同时操作相同的数据时。
常见场景包括:
- 不同顺序访问资源:事务A先操作表1再操作表2,事务B先操作表2再操作表1。
- 索引缺失:全表扫描导致锁范围扩大,增加冲突概率。
- 长事务:事务长时间未提交,导致锁持有时间过长。
二、死锁场景复现(以MySQL为例)
- 复现死锁可以帮助理解问题发生的条件,从而更好地预防和解决。
1. 准备测试表和数据
CREATE TABLE account (
    id INT PRIMARY KEY,
    balance DECIMAL(10,2)
);
INSERT INTO account VALUES (1, 1000.00), (2, 2000.00);
2. 模拟两个事务交叉更新
- 事务A:先更新id=1,再更新id=2。 - BEGIN;
UPDATE account SET balance = balance - 100 WHERE id = 1;
UPDATE account SET balance = balance + 100 WHERE id = 2;
COMMIT;
 
- 事务B:先更新id=2,再更新id=1。 - BEGIN;
UPDATE account SET balance = balance - 200 WHERE id = 2;
UPDATE account SET balance = balance + 200 WHERE id = 1;
COMMIT;
 
3. 观察死锁
- 按顺序执行事务A和事务B的UPDATE语句。
- 事务A尝试更新id=2时,因事务B持有锁而等待。
- 事务B尝试更新id=1时,因事务A持有锁而等待。
- 数据库检测到死锁,自动回滚其中一个事务:1205 - Lock wait timeout exceeded; try restarting transaction
 

三、解决死锁的核心方法
- 常见的解决策略包括设置合理的事务隔离级别、优化事务逻辑、使用超时机制、以及数据库自动检测和处理死锁。
1. 数据库自动处理
2. 代码层优化
- 统一资源访问顺序:所有事务按相同顺序操作表或记录。
UPDATE account SET ... WHERE id = 1;
UPDATE account SET ... WHERE id = 2;
 
- 减少事务粒度:避免长事务,尽快提交或回滚。
@Transactional(timeout = 5)  
public void transfer() { ... }
 
- 使用乐观锁:通过版本号避免行锁竞争。UPDATE account 
SET balance = 900, version = version + 1 
WHERE id = 1 AND version = 1;
 
3. 数据库配置调优
4. 重试机制
四、死锁分析工具
- MySQL死锁日志: - 查看SHOW ENGINE INNODB STATUS输出,分析TRANSACTION和WAITING FOR THIS LOCK部分。
 
- pt-deadlock-logger(Percona工具):
 实时监控死锁事件并记录。
 - pt-deadlock-logger --user=root --password=123456 --run-time=10
 
- 性能模式(Performance Schema):
 MySQL 5.6+开启性能模式,监控锁等待事件。
 - SELECT * FROM performance_schema.events_transactions_current;
 

五、预防死锁
- 事务设计原则:
- 统一操作顺序:
 所有业务逻辑按固定顺序访问资源(如按主键升序操作)。
- 监控与报警:
 配置Prometheus监控死锁次数,超过阈值触发告警。
- 压力测试:
 使用JMeter模拟并发事务,验证死锁概率。
六、总结
- 复现死锁:通过交叉更新不同顺序的资源,观察数据库自动回滚。
- 解决方案:- 统一资源访问顺序,减少锁竞争。
- 优化索引和事务设计,降低死锁概率。
- 结合重试机制和数据库自动处理,提升系统容错性。
 
- 关键工具:数据库日志、性能分析工具、压力测试框架。
转自https://juejin.cn/post/7481837718718644274
该文章在 2025/3/17 10:33:31 编辑过