1

我需要这方面的专家建议。

后台 PHP/Codeigniter MYSQLi Innodb 表 - fares_table 存储过程

后端 - 每隔几分钟编写一个 cronjob php 脚本以将数据(来自服务)插入/更新到 fares_table 中。(普通sql查询)

前端 - 用户将能够读取这些数据(查询以存储过程形式编写,因为它涉及连接许多表,因此我的存储过程已从 fares_table 的 select 语句创建临时表并连接到其他表)

问题

尝试获取锁时发现死锁;尝试重启事务

如果用户碰巧在 fares_table 更新/插入时偶然发现前端,则可能会发生死锁。更新语句发生死锁

死锁是由于存储过程试图等待锁定释放,同时尝试使用来自 fares_table 的 select 语句创建临时表,而后端执行插入或更新尝试等待锁定释放。

LATEST DETECTED DEADLOCK
------------------------
110408  9:05:45
*** (1) TRANSACTION:
TRANSACTION 0 203543446, ACTIVE 0 sec, OS thread id 6584 fetching rows
mysql tables in use 2, locked 2
LOCK WAIT 761 lock struct(s), heap size 60736, 30170 row lock(s)
MySQL thread id 86268, query id 135039790 XXXXXXX Copying to t
CREATE TEMPORARY TABLE tmp_tb1 AS SELECT MIN( fare ) as cheapest_fare,flighttype origin,destination ....
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table`
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
0: len 4; hex 8025d996; asc  %  ;; 1: len 6; hex 00000c21d3a9; asc    !  ;; 2: len 7; hex 0000000b031

*** (2) TRANSACTION:
TRANSACTION 0 203543465, ACTIVE 0 sec, OS thread id 3080 updating or deleting, thread declared inside
mysql tables in use 1, locked 1
3 lock struct(s), heap size 320, 2 row lock(s), undo log entries 1
MySQL thread id 85631, query id 135039816 XXXXX Updating
UPDATE `fares_table` SET `fare` = 2552.85, `currency` = 'AUD'..
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 18433 n bits 240 index `PRIMARY` of table `db_name`.`fares_table`
Record lock, heap no 85 PHYSICAL RECORD: n_fields 18; compact format; info bits 0
0: len 4; hex 8025d996; asc  %  ;; 1: len 6; hex 00000c21d3a9; asc    !  ;; 2: len 7; hex 0000000b031

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 2086 n bits 600 index `flighttype_idx` of table `db_name`.`fares_table`
Record lock, heap no 218 PHYSICAL RECORD: n_fields 4; compact format; info bits 0
0: len 7; hex 4f6e6520776179; asc One way;; 1: len 3; hex 424e45; asc BNE;; 2: len 8; hex 8000124a588

*** WE ROLL BACK TRANSACTION (2)

我的临时修复

捕获数据库错误 1213 并重试更新查询。它现在可以工作,但我想找到一个更好的解决方案来防止死锁。有什么专业建议吗?

我如何更改顺序以防止死锁或重复索引的flighttype_idx帮助?

4

1 回答 1

0

由于创建临时表的查询由于聚合函数本质上需要锁定表的主要部分MIN(fare),并且票价更新需要等待其完成,因此没有简单的重新排序可以解决死锁。

最好通过显式锁定机制来包围争用,也许只是为了这个目的而在锁定表上,而不是让事务竞争然后不得不回滚。特别是,create table 语句不能回滚,这可能看起来很奇怪。请参阅LOCK TABLE 文档

为了整洁地实现,将票价更新语句移动到存储过程中,并让票价更新和临时表创建存储过程循环检查和设置锁定,完成它们的工作,然后解锁。

于 2011-04-11T05:09:36.600 回答