MySQL更新死锁问题

作为一个社交类的 App ,我们有很多操作都会同时发生,为了确保数据的一致性,会采用数据库的事物。

比如现在我们有一个点赞操作,点赞成功后,需要更改文章的热度。以下是 SQL 语句:

INSERT INTO user_praise(uid,plan_id,stage_id) VALUES(123456,14456,10023);

UPDATE plan_hot SET hot = hot + 1 WHERE plan_id = 14456;

在这里我们需要用到事物来确保它的原子性,也就是要么这两条语句全部执行成功,要么就全部回滚。

问题出现

在本地这么测试后,发现并没有出现什么问题,但是部署上线后,打印出了错误日志,如下

### Error updating database.  
### Cause: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction ### The error occurred while setting parameters SQL: UPDATE plan_hot SET hot = hot + 1 WHERE plan_id = ?; 

错误中提示下面的更新语句出现了死锁

UPDATE plan_hot SET hot = hot + 1 WHERE plan_id = ?;

该问题是第一次遇到,大概也知道是哪里出现了死锁,就是更新 hot = hot + 1 的时候,hot 可能会被一个锁锁住,而下一个操作就需要等待释放锁,然后才能获取到 hot 的值,进行 hot = hot + 1。如果操作过快的话,可能就会造成死锁。

但是还是不懂为什么会这样,根本原因是什么,于是查资料,发现有一个小伙伴解释得蛮清晰的,下面是他的博文。

分析解决

问题分析及解决方案参考

MySQL更新死锁问题

谢谢他的分享,也希望更多的朋友能分享经验。

http://www.tuicool.com/articles/nQniiaa

 

转载于:https://www.cnblogs.com/softidea/p/5816502.html

MySQL 线上环境中,死锁问题通常出现在高并发场景下,当多个事务相互持有资源并请求对方持有的资源时,就会进入死锁状态。为了解决此类问题,需要从死锁的成因、排查方法以及预防策略三个方面进行分析和处理。 ### 死锁的成因 MySQL 中的死锁通常与事务的锁机制密切相关,尤其是在使用 InnoDB 存储引擎时,其支持行级锁、间隙锁和临键锁(Next-Key Lock)等锁类型。当多个事务对相同的资源(如表、行、索引)进行加锁操作时,如果锁的请求顺序不一致,就可能导致死锁。例如,事务 A 持有行 R1 的锁并请求行 R2 的锁,而事务 B 持有行 R2 的锁并请求行 R1 的锁,此时两个事务将陷入死锁状态[^3]。 ### 死锁的排查方法 1. **查看死锁日志** MySQL 提供了 `SHOW ENGINE INNODB STATUS` 命令,可以输出当前 InnoDB 存储引擎的状态信息,其中包括最近一次死锁的详细信息。通过分析该日志,可以了解死锁发生时的事务等待资源情况、持有的锁以及涉及的 SQL 语句。例如,日志中会显示事务等待的锁类型、事务持有的锁以及事务执行的 SQL 语句。 2. **分析事务等待图** 通过分析死锁日志中的事务等待图,可以确定事务之间的依赖关系。如果事务之间存在循环依赖,则说明发生了死锁。事务等待图通常包括事务的 ID、事务等待的锁资源以及事务持有的锁资源。 3. **检查 SQL 执行顺序** 在高并发场景下,SQL 语句的执行顺序可能会导致死锁。例如,多个事务按照不同的顺序访问相同的资源时,可能会产生锁冲突。因此,检查 SQL 语句的执行顺序是排查死锁的重要步骤。 4. **监控锁等待时间** 通过监控数据库的锁等待时间,可以发现潜在的锁竞争问题。如果某些事务的锁等待时间过长,则可能表明存在死锁风险。 ### 死锁的解决方案 1. **调整事务的执行顺序** 确保多个事务按照相同的顺序访问资源,可以有效避免死锁。例如,在执行更新操作时,按照主键的顺序依次更新数据,可以减少锁冲突的可能性。 2. **减少事务的持有锁时间** 尽量减少事务的执行时间,可以在事务中减少不必要的操作,例如避免在事务中执行复杂的计算或长时间的查询。事务越短,锁的持有时间越短,死锁的概率就越低。 3. **优化 SQL 语句** 优化 SQL 语句可以减少锁的持有范围和锁的粒度。例如,避免全表扫描,尽量使用索引进行查询和更新操作,以减少锁的范围。同时,避免在事务中执行不必要的 SQL 语句,以减少锁的竞争。 4. **使用死锁检测机制** MySQL 的 InnoDB 存储引擎内置了死锁检测机制,当检测到死锁时,会自动选择一个事务进行回滚,以解除死锁状态。可以通过调整 `innodb_deadlock_detect` 参数来启用或禁用死锁检测机制。 5. **设置合理的超时时间** 通过设置 `innodb_lock_wait_timeout` 参数,可以控制事务等待锁的最长时间。如果事务等待锁的时间超过该值,则会自动回滚。合理设置超时时间可以避免事务长时间等待,减少死锁的影响。 ### 示例:死锁日志分析 以下是一个典型的死锁日志示例: ```sql LATEST DETECTED DEADLOCK ------------------------ ...事务等待图信息... ...事务持有的锁资源... ...事务等待的锁资源... ...事务执行的SQL语句... ``` 通过分析日志中的事务等待图和 SQL 语句,可以确定死锁的具体原因,并采取相应的优化措施。 ### 相关问题 1. 如何通过 `SHOW ENGINE INNODB STATUS` 分析死锁日志? 2. 在 MySQL 中,如何优化 SQL 语句以减少锁冲突? 3. 什么是事务的等待图,如何通过它排查死锁? 4. 如何设置合理的 `innodb_lock_wait_timeout` 参数值? 5. 死锁检测机制是如何工作的,是否会影响数据库性能?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值