面试题答案
一键面试锁粒度优化
- 行级锁:在高并发读写场景下,优先使用行级锁。因为表级锁会锁定整张表,限制并发度。而行级锁只锁定需要操作的行,能提高并发性能。例如在电商订单表中,多个用户同时购买不同商品,每个订单插入操作只需要锁定对应的行,而不是整个订单表。但行级锁的开销比表级锁大,需要权衡。
- 页级锁:介于表级锁和行级锁之间,锁定的是数据页。适合某些特定场景,如InnoDB存储引擎中的辅助索引的插入操作,可能会使用页级锁。例如在一个频繁插入的日志表中,页级锁可以在一定程度上平衡并发和锁开销。
锁超时设置
- 合理设置锁等待超时时间:根据业务场景,设置合适的锁等待超时时间。如果设置过短,可能导致一些正常的操作因为短暂的锁等待而失败;设置过长,会导致等待锁的线程长时间占用资源。例如,对于实时性要求不高的批量数据导入操作,可以适当设置较长的锁等待时间,如30秒;而对于实时交易操作,可能设置较短的锁等待时间,如5秒。
- 动态调整超时时间:可以根据系统负载情况动态调整锁等待超时时间。例如,在系统负载较低时,适当缩短超时时间,让请求快速失败并尝试重新获取锁;在系统负载较高时,适当延长超时时间,避免过多请求因锁等待超时失败。
死锁检测与预防
- 死锁检测:MySQL InnoDB引擎默认开启死锁检测机制。当检测到死锁时,InnoDB会自动回滚其中一个事务来打破死锁。例如,事务A持有行X的锁并请求行Y的锁,同时事务B持有行Y的锁并请求行X的锁,此时就会发生死锁,InnoDB会检测到并选择回滚其中一个事务。
- 死锁预防:
- 按相同顺序访问资源:确保所有事务以相同的顺序访问资源,这样可以避免死锁。例如,在涉及多个表操作的事务中,所有事务都先访问表A,再访问表B,以此类推。
- 减少锁持有时间:尽量缩短事务持有锁的时间,尽快释放锁资源。例如,将大事务拆分成多个小事务,每个小事务只在必要时获取锁并尽快释放。
示例
假设有一个银行转账的场景,从账户A向账户B转账。如果使用表级锁,在转账操作期间,整个账户表都会被锁定,其他转账操作都要等待。但如果使用行级锁,只锁定账户A和账户B对应的行,其他账户的操作可以并发进行。同时,设置合理的锁等待超时时间,如10秒,防止因网络波动等原因导致长时间等待。并且通过确保所有转账事务按相同顺序获取账户锁(如先获取转出账户锁,再获取转入账户锁),来预防死锁。