事务处理:死锁避免(教师版)¶
作者:teacher 更新日期:2024-12-19
问题描述¶
在高并发数据库系统中,死锁是常见的问题。当多个事务相互等待对方释放锁时,就会发生死锁,导致系统性能下降甚至服务中断。
死锁产生的原因¶
- 资源竞争: 多个事务同时访问相同的数据资源
- 锁顺序不一致: 不同事务以不同顺序获取锁
- 长时间持有锁: 事务执行时间过长,锁持有时间过久
预防策略¶
1. 资源有序分配¶
-- 错误示例:可能导致死锁
-- 事务A: 先锁用户表,再锁订单表
-- 事务B: 先锁订单表,再锁用户表
-- 正确做法:统一锁顺序
-- 所有事务都按相同顺序获取锁
BEGIN;
SELECT * FROM users WHERE id = 1 FOR UPDATE;
SELECT * FROM orders WHERE user_id = 1 FOR UPDATE;
COMMIT;
2. 设置锁超时¶
-- MySQL
SET innodb_lock_wait_timeout = 10;
-- PostgreSQL
SET lock_timeout = '10s';
3. 使用合适的隔离级别¶
-- 根据业务需求选择合适的隔离级别
-- READ COMMITTED: 减少锁持有时间
SET TRANSACTION ISOLATION LEVEL READ COMMITTED;
检测和解决¶
死锁检测¶
-- MySQL 查看死锁信息
SHOW ENGINE INNODB STATUS;
-- PostgreSQL 查看锁等待
SELECT * FROM pg_locks WHERE NOT granted;
死锁处理¶
- 自动回滚: 数据库自动选择一个事务进行回滚
- 重试机制: 应用层实现重试逻辑
- 监控告警: 建立死锁监控和告警机制
最佳实践¶
- 保持事务简短
- 按固定顺序访问资源
- 使用合适的索引减少锁范围
- 考虑使用乐观锁替代悲观锁
- 建立完善的监控体系
扩展思考¶
- 如何设计重试机制?
- 乐观锁和悲观锁的适用场景?
- 如何监控数据库死锁情况?