面试题答案
一键面试死锁产生原因
- 资源竞争:多个事务同时竞争有限的资源,例如多个事务试图同时获取同一行数据的锁,且获取锁的顺序不一致。
- 事务操作顺序:不同事务对资源的访问顺序不同,形成循环等待的情况。例如事务A获取了资源X的锁,事务B获取了资源Y的锁,然后事务A试图获取资源Y的锁,事务B试图获取资源X的锁,从而导致死锁。
MySQL内部死锁检测
- 等待图(Wait-for Graph):MySQL通过维护一个等待图来检测死锁。在等待图中,节点代表事务,边表示事务之间的等待关系。当一个事务请求锁时,如果该锁已经被其他事务持有,MySQL会在等待图中添加一条从当前事务到持有锁事务的边。
- 周期性检测:MySQL会定期检查等待图是否存在环。如果存在环,就意味着发生了死锁。
MySQL解决死锁机制
- 选择牺牲者:一旦检测到死锁,MySQL会选择一个事务作为牺牲者(Victim),通常选择回滚代价最小的事务。回滚代价可以通过事务已执行的操作数、已获取的锁数等因素来衡量。
- 回滚牺牲者事务:MySQL将牺牲者事务回滚,释放该事务持有的所有锁,使得其他事务能够继续执行。
开发人员预防措施
- 优化事务逻辑:尽量减少事务的执行时间和资源占用,将大事务拆分成小事务,降低死锁发生的概率。
- 按相同顺序访问资源:确保多个事务以相同的顺序访问资源,避免形成循环等待。例如,所有事务都先获取资源A的锁,再获取资源B的锁。
- 降低锁的粒度:尽量使用行级锁而非表级锁,减少锁冲突的范围。
- 合理设置事务隔离级别:根据业务需求选择合适的事务隔离级别,不同隔离级别对锁的使用和死锁的发生概率有影响。例如,READ COMMITTED隔离级别相对REPEATABLE READ隔离级别,锁的使用可能更宽松,死锁概率可能降低。
- 设置合理的锁等待超时时间:通过设置
innodb_lock_wait_timeout
参数,控制事务等待锁的最长时间,避免无限期等待。如果等待时间超过该值,事务会自动回滚,防止死锁长时间占用资源。