0

I'm stuck and confused by a MySQL InnoDB Deadlock. I've run my unit tests on an H2 DB and everything runs properly. However, running against a MySQL DB (isolation: REPEATABLE_READ or READ_COMMITTED) fails.

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)
    .....
    .....

When I look at the InnoDB Engine status (show engine innodb status), I see the following:

------------------------
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;

I see the deadlock is occuring around the following SQL:

update contract set version = version + 1 where id = 3

So I updated my test to simply execute 50 simultaneous update transactions, but I cannot replicate it with a such a basic test. So I'm relegated to looking at the status to try and determine why/how this simple SQL could cause a deadlock.

Is anyone able to better understand the log and explain what is happening? I see that T1 is waiting for an eXclusive lock, T2 has a Shared lock and is also waiting on an eXclusive lock. But I don't understand why MySQL doesn't issue the eXclusive lock to T2 then instead of rolling back the transaction.

And even more importantly, how do I resolve this? I saw another post on StackOverflow that points to an AOP solution to retry the transaction, but that seems more like a hack than really solving the issue.

Is there a way to really trace the lock allocation/release to see exactly what sequence is causing the error?

Community
  • 1
  • 1
Eric B.
  • 23,425
  • 50
  • 169
  • 316
  • do you use autocommit true or false? – Iłya Bursov Jul 11 '14 at 20:37
  • @Lashane autocommit is ON – Eric B. Jul 11 '14 at 20:45
  • do you use any kind of triggers or stored procedures? – Iłya Bursov Jul 11 '14 at 20:45
  • @Lashane No - there are no triggers or stored procedures at all. – Eric B. Jul 11 '14 at 20:47
  • @Lashane - Actually, after further investigation, I noticed that although autocommit is enabled as a DB default, Spring is disabling it as Spring is handling the transactions itself. – Eric B. Jul 11 '14 at 20:54
  • ok, as far as I see from this log - problem is not with this query, but with surrounding queries, try to find all queries related to `josak_unit_tests` table and find out where deadlock can occur (ie two different threads trying to update/insert into this table) – Iłya Bursov Jul 11 '14 at 20:56
  • @Lashane I'm confused though. If it isn't these two transactions causing the deadlock, why would rolling back T2 relieve the deadlock? With an InnoDB tablespace, am I looking for anything that reads the `contract` table, writes to it, or reads/writes the specific record (where id = 3)? – Eric B. Jul 11 '14 at 21:02
  • transaction is not sql query, these 2 transactions causing deadlock – Iłya Bursov Jul 11 '14 at 21:06
  • you need to find all queries related to both tables, find out in what order they are called and find the reason of deadlock – Iłya Bursov Jul 11 '14 at 21:11
  • as quick and dirty solution - you can execute commit after any update – Iłya Bursov Jul 11 '14 at 21:12
  • @Lashane There are 3 queries that occur within the transaction. But this is the only query that affects the `contracts` table. – Eric B. Jul 12 '14 at 02:50

0 Answers0