我被MySQL InnoDB死锁困住了。我在H2 DB上运行我的单元测试,一切运行正常。但是,针对MySQL DB(隔离:REPEATABLE_READ或READ_COMMITTED)运行失败。
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLTransactionRollbackException: Deadlock found when trying to get lock; try restarting transaction
at sun.reflect.GeneratedConstructorAccessor55.newInstance(Unknown Source)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
.....
.....
当我查看InnoDB引擎状态(show engine innodb status
)时,我看到以下内容:
------------------------
LATEST DETECTED DEADLOCK
------------------------
140711 15:23:48
*** (1) TRANSACTION:
TRANSACTION 0 1395766, ACTIVE 0 sec, OS thread id 4351500288 starting index read
mysql tables in use 1, locked 1
LOCK WAIT 7 lock struct(s), heap size 1216, 3 row lock(s), undo log entries 2
MySQL thread id 5, query id 746 localhost 127.0.0.1 test Updating
update contract set version = version + 1 where id = 3
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 3650 n bits 72 index `PRIMARY` of table `unit_tests`.`contract` trx id 0 1395766 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 14; compact format; info bits 0
0: len 8; hex 8000000000000003; asc ;; 1: len 6; hex 000000154c2f; asc L/;; 2: len 7; hex 0000000e751814; asc u ;; 3: len 8; hex 800012515fefa719; asc Q_ ;; 4: len 8; hex 800012515fefa719; asc Q_ ;; 5: len 12; hex 6e756d6265725f3132333435; asc number_12345;; 6: len 10; hex 747970655f3132333435; asc type_12345;; 7: len 8; hex 800012515fefa7ee; asc Q_ ;; 8: len 8; hex 800012515fefa7ba; asc Q_ ;; 9: len 4; hex 80000008; asc ;; 10: len 12; hex 766f6c756d655f3132333435; asc volume_12345;; 11: SQL NULL; 12: SQL NULL; 13: SQL NULL;
*** (2) TRANSACTION:
TRANSACTION 0 1395765, ACTIVE 0 sec, OS thread id 4385959936 starting index read, thread declared inside InnoDB 500
mysql tables in use 1, locked 1
8 lock struct(s), heap size 1216, 4 row lock(s), undo log entries 2
MySQL thread id 9, query id 751 localhost 127.0.0.1 test Updating
update contract set version = version + 1 where id = 3
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 0 page no 3650 n bits 72 index `PRIMARY` of table `unit_tests`.`contract` trx id 0 1395765 lock mode S locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 14; compact format; info bits 0
0: len 8; hex 8000000000000003; asc ;; 1: len 6; hex 000000154c2f; asc L/;; 2: len 7; hex 0000000e751814; asc u ;; 3: len 8; hex 800012515fefa719; asc Q_ ;; 4: len 8; hex 800012515fefa719; asc Q_ ;; 5: len 12; hex 6e756d6265725f3132333435; asc number_12345;; 6: len 10; hex 747970655f3132333435; asc type_12345;; 7: len 8; hex 800012515fefa7ee; asc Q_ ;; 8: len 8; hex 800012515fefa7ba; asc Q_ ;; 9: len 4; hex 80000008; asc ;; 10: len 12; hex 766f6c756d655f3132333435; asc volume_12345;; 11: SQL NULL; 12: SQL NULL; 13: SQL NULL;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 0 page no 3650 n bits 72 index `PRIMARY` of table `unit_tests`.`contract` trx id 0 1395765 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 14; compact format; info bits 0
0: len 8; hex 8000000000000003; asc ;; 1: len 6; hex 000000154c2f; asc L/;; 2: len 7; hex 0000000e751814; asc u ;; 3: len 8; hex 800012515fefa719; asc Q_ ;; 4: len 8; hex 800012515fefa719; asc Q_ ;; 5: len 12; hex 6e756d6265725f3132333435; asc number_12345;; 6: len 10; hex 747970655f3132333435; asc type_12345;; 7: len 8; hex 800012515fefa7ee; asc Q_ ;; 8: len 8; hex 800012515fefa7ba; asc Q_ ;; 9: len 4; hex 80000008; asc ;; 10: len 12; hex 766f6c756d655f3132333435; asc volume_12345;; 11: SQL NULL; 12: SQL NULL; 13: SQL NULL;
我看到围绕以下SQL发生了死锁:
update contract set version = version + 1 where id = 3
所以我更新了我的测试以简单地执行50个同步更新事务,但我无法通过这样的基本测试来复制它。因此,我倾向于查看状态以尝试确定这个简单SQL可能导致死锁的原因/方式。
是否有人能够更好地了解日志并解释发生了什么?我看到T1正在等待一个eXclusive锁,T2有一个共享锁,并且还在等待一个eXclusive锁。但我不明白为什么MySQL不向T2发出eXclusive锁定,而不是回滚事务。
更重要的是,我该如何解决这个问题?我看到another post on StackOverflow指向AOP解决方案来重试事务,但这似乎更像是一个黑客而不是真正解决问题。
有没有办法真正跟踪锁定分配/释放,以确切了解导致错误的序列是什么?