1. 监控与识别死锁
要解决MySQL死锁问题,首先需定位死锁来源。常用方法包括:
/var/log/mysql/error.log,通过sudo tail -f /var/log/mysql/error.log实时监控,搜索“Deadlock found”或“Lock wait timeout exceeded”关键词,可快速定位死锁事件。SHOW ENGINE INNODB STATUS\G,输出中的“LATEST DETECTED DEADLOCK”部分会详细展示最近死锁的事务ID、SQL语句、锁类型(如行锁、间隙锁)及等待关系,是分析死锁根源的关键依据。2. 分析死锁根本原因
通过监控工具获取死锁信息后,需深入分析其成因,常见场景包括:
3. 优化事务设计与SQL语句
针对死锁原因,优化事务逻辑与SQL是预防死锁的核心:
ALTER TABLE orders ADD INDEX idx_user_product (user_id, product_id)),缩小锁范围,降低锁冲突。SELECT ... FOR UPDATE(仅在必要时加锁),减少锁占用范围。4. 调整MySQL配置参数
通过配置参数平衡并发性能与死锁风险:
SET GLOBAL innodb_lock_wait_timeout = 50;(默认50秒)调整事务等待锁的最长时间,超时后自动回滚,避免无限期等待。innodb_deadlock_detect参数为ON(默认开启),MySQL会自动检测死锁并回滚其中一个事务,快速解除死锁状态。my.cnf中添加innodb_print_all_deadlocks = ON,将所有死锁信息记录到错误日志,便于后续统计分析与模式识别。5. 应用程序层面实现重试机制
死锁发生时,MySQL会自动回滚其中一个事务,但应用程序需具备容错能力:
import mysql.connector
from mysql.connector import Error
import time
def execute_with_retry(query, max_retries=3):
for attempt in range(max_retries):
try:
connection = mysql.connector.connect(
host='localhost',
database='your_database',
user='your_user',
password='your_password'
)
cursor = connection.cursor()
cursor.execute("BEGIN")
cursor.execute(query)
connection.commit()
cursor.close()
connection.close()
return True
except Error as e:
if e.errno == 1213: # 死锁错误码
print(f"Deadlock detected, retrying... (Attempt {attempt + 1}/{max_retries})")
time.sleep(0.1 * (2 ** attempt)) # 指数退避
else:
raise e
return False
# 使用示例
query = "UPDATE your_table SET column1 = 'value' WHERE id = 1"
if not execute_with_retry(query):
print("Failed to execute query after multiple retries due to deadlock.")
6. 定期维护与预防
ANALYZE TABLE更新表统计信息,OPTIMIZE TABLE整理表碎片,提升查询效率,减少锁持有时间。