面试题答案
一键面试死锁产生的原因
- 资源竞争:多个事务同时竞争相同的资源(如行锁),并且每个事务都持有部分资源,同时又请求其他事务已持有的资源,形成循环等待的局面。例如,事务A持有行1的锁并请求行2的锁,而事务B持有行2的锁并请求行1的锁,这就导致了死锁。
- 锁顺序不一致:不同事务以不同顺序获取锁,若顺序不当,容易造成死循环等待。比如事务1按顺序获取锁a和锁b,而事务2按顺序获取锁b和锁a,如果两个事务同时执行,就可能出现死锁。
应用开发层面避免死锁的措施
- 按照固定顺序获取锁:在应用程序中,对多个资源加锁时,所有事务都按照相同的顺序获取锁。例如,如果一个事务需要获取行1和行2的锁,所有相关事务都先获取行1的锁,再获取行2的锁,这样就不会形成循环等待。
- 减少锁的持有时间:尽量缩短事务持有锁的时间,在获取锁后尽快完成操作并释放锁。这样可以降低其他事务等待锁的时间,减少死锁发生的概率。例如,将大事务拆分成多个小事务,在每个小事务中尽快完成对资源的操作并提交。
- 设置合理的事务超时:为事务设置一个合理的超时时间,如果事务在规定时间内无法获取到所需的锁,就自动回滚。这样可以避免事务无限期等待锁,从而减少死锁的可能性。例如,使用
SET statement_timeout = <timeout_value>
语句设置事务超时时间(单位为毫秒)。 - 重试机制:当检测到死锁并回滚事务后,应用程序可以进行重试。在重试前,可以等待一段随机时间,避免多个事务同时重试再次导致死锁。例如,使用指数退避算法来确定重试的时间间隔,随着重试次数增加,间隔时间逐渐变长。
数据库配置层面避免死锁的措施
- 死锁检测:PostgreSQL默认开启死锁检测机制。数据库系统会定期检查是否存在死锁情况,一旦检测到死锁,会选择一个事务进行回滚(通常选择代价最小的事务)来打破死锁。可以通过
deadlock_timeout
参数来设置死锁检测的超时时间(单位为毫秒),默认值为1000毫秒。适当调整该参数可以优化死锁检测的频率和响应速度。 - 优化数据库参数:合理调整与锁相关的参数,如
max_locks_per_transaction
,该参数限制了一个事务可以持有的最大锁数量。通过调整该参数,可以控制事务持有锁的规模,从而降低死锁发生的风险。但需要注意,设置过小可能会影响事务的正常执行,需要根据实际业务场景进行评估和调整。