1

我面临以下异常:

com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction

我可以说的是,我有多个线程在同一张表上并行执行查询。但我不明白为什么会发生这种异常。因为如果一个查询锁定了一张表,那么另一个线程中的同一个查询(或同一张表上的其他查询)将等待锁定。死锁是怎么产生的?

我换个说法,我理解异常,但我不明白的是一个查询正在等待另一个查询,另一个查询应该执行,离开锁,等待查询可以获得锁,为什么死锁?

如果有人想查看实际的查询(这些查询在多个线程中以与此处打印的顺序相同的顺序执行,没有任何事务):

UPDATE daily_stats, account, campaign SET campaign_messages_cost = campaign_messages_cost + (IF(current_free_sms >= ?, campaign.campaign_cost, campaign.campaign_cost + (account.sms_charging_rate * ? ))), campaign_messages_delivered_count = campaign_messages_delivered_count + 1 WHERE daily_stats_id = ? AND campaign.id = ? AND daily_stats.account_id = account.id

update account a JOIN campaign b ON a.id = b.account_id set campaign_cost = IF(current_free_sms >= ?, campaign_cost, campaign_cost + (a.sms_charging_rate * ? )), delivered_count = delivered_count + ?, credit = IF(current_free_sms >= ?, credit, credit - (a.sms_charging_rate * ?)), current_free_sms = IF (current_free_sms >= ?, current_free_sms - ?, current_free_sms) where b.id = ?
4

1 回答 1

1

MySQL 将任何查询语句视为事务(至少在使用默认 InnoDB 引擎时),但如果 @@autocommit 变量设置为 1(默认值),所有语句都会立即自动提交,从而有效地隐藏事务发生。尽管没有开始/提交/回滚,这可以解释“发现死锁”错误,尽管错误消息的“回滚”部分有点神秘,而且我以前没有见过。

MySQLs 提出的处理死锁的方法是组合查询结构以最小化问题,以及编写代码在它们发生时处理它们——因为它们将在像你这样的软件中。我的方法很简单但很有效:睡眠 500 毫秒并重试。在处理相当高负载的系统上(尽管在公司环境中),我很少看到超过两次连续重试。

您还应该查看有关如何处理死锁的 MySQL 建议。

于 2013-04-04T12:26:32.060 回答