In my application, a deadlock occurs when I run queries that are almost the same.
When I ran a SHOW ENGINE INNODB STATUS, result is same as follows. (InnoDB, mysql5.7)
*** (1) TRANSACTION:
TRANSACTION 41516159, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 7 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 25
MySQL thread id 266983, OS thread handle 47538359256832, query id 156835755 172.31.5.225 Test_Table updating
Update Test_Table SET updatedAt = '2021-11-01 23:59:59' WHERE PK = 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 142 page no 542 n bits 0 index PRIMARY of table `Test_Table` trx id 41516159 lock_mode X locks rec but not gap waiting
Record lock, heap no 68 PHYSICAL RECORD: n_fields 23; compact format; info bits 0
*** (2) TRANSACTION:
TRANSACTION 41516160, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 7 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 25
MySQL thread id 266996, OS thread handle 47549115574016, query id 156835795 XXX.XX.XX.XX Test_Table updating Update Test_Table SET updatedAt = '2021-11-01 23:59:58' WHERE PK = 1
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 142 page no 542 n bits 0 index PRIMARY of table `Test_Table` trx id 41516160 lock mode S locks rec but not gap Record lock, heap no 68 PHYSICAL RECORD: n_fields 23; compact format; info bits 0
I can't understand why update query make a s-lock.
I have 2 tables EXPERIMENT and ENTITIES. ENTITIES has an id field which references primary Id of table EXPERIMENT.
I inserted multiple experiments along with the child entities concurrently and got deadlocks.
show engine innodb status shows the debugging information.
I am unable to find why the deadlock occured. I guess that it happened because the child entities is verifying the Foreign_Key in the experiment table, but that doesn't look like it should generate deadlock.
I am using AUTO INCREMENT for the id's and SERIALIZABLE transaction ISOLATION.
Here is the relevant section from the innodb status :
------------------------
LATEST DETECTED DEADLOCK
------------------------
2019-05-14 12:34:45 0x7000060f3000
*** (1) TRANSACTION:
TRANSACTION 162916, ACTIVE 1 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 10 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 2
MySQL thread id 183, OS thread handle 123145405919232, query id 2464 localhost 127.0.0.1 root update
INSERT INTO _ENTITIES (TYPE, FK_EXPERIMENT_ID, CONTENT, CREATED_USER_ID) VALUES ('VARIATION', 42, '{"variantName":"Variant 1","actions":[{"blockId":0,"type":"SendEmail","criteria":{"and":[{"operator":"EQ","attr":"_id","val":"Test","ruleId":1,"category":"default"},{"operator":"EQ","attr":"productLanguage","val":"CS_CZ","ruleId":1,"category":"contextual"}]},"order":1,"surfaceActionName":"EMAIL","params":{"verified":true,"selectedTemplate":"Design-Paid-Portfolio-A"},"name":"Action Block 1","treatmentId":"","default":true},{"blockId":1,"type":"wait","criteria":{"and":[{"operator":"EQ","attr":"_id","val":"Test","ruleId":1,"category":"default"},{"operator":"EQ","attr":"productLanguage","val":"CS_CZ","ruleId":1,"category":"contextual"}]},"order":1,"surfaceActionName":"wait","params":{"unit":"hour","data":10,"verified":true},"name":"Action Block 1","treatmentId":"","default":true}],"variantPercentage":80}', 'uk
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6728 page no 4 n bits 96 index ENTITIES_EXPERIMENT_ID of table `test_database`.`_entities` trx id 162916 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) TRANSACTION:
TRANSACTION 162906, ACTIVE 1 sec inserting
mysql tables in use 1, locked 1
8 lock struct(s), heap size 1136, 4 row lock(s), undo log entries 2
MySQL thread id 164, OS thread handle 123145403969536, query id 2549 localhost 127.0.0.1 root update
INSERT INTO _ENTITIES (TYPE, FK_EXPERIMENT_ID, CONTENT, CREATED_USER_ID) VALUES ('VARIATION', 33, '{"variantName":"Variant 1","actions":[{"blockId":0,"type":"SendEmail","criteria":{"and":[{"operator":"EQ","attr":"_id","val":"Test","ruleId":1,"category":"default"},{"operator":"EQ","attr":"productLanguage","val":"CS_CZ","ruleId":1,"category":"contextual"}]},"order":1,"surfaceActionName":"EMAIL","params":{"verified":true,"selectedTemplate":"Design-Paid-Portfolio-A"},"name":"Action Block 1","treatmentId":"","default":true},{"blockId":1,"type":"wait","criteria":{"and":[{"operator":"EQ","attr":"_id","val":"Test","ruleId":1,"category":"default"},{"operator":"EQ","attr":"productLanguage","val":"CS_CZ","ruleId":1,"category":"contextual"}]},"order":1,"surfaceActionName":"wait","params":{"unit":"hour","data":10,"verified":true},"name":"Action Block 1","treatmentId":"","default":true}],"variantPercentage":80}', 'uk
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 6728 page no 4 n bits 96 index ENTITIES_EXPERIMENT_ID of table `test_database`.`_entities` trx id 162906 lock mode S
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 6728 page no 4 n bits 96 index ENTITIES_EXPERIMENT_ID of table `test_database`.`_entities` trx id 162906 lock_mode X insert intention waiting
Record lock, heap no 1 PHYSICAL RECORD: n_fields 1; compact format; info bits 0
0: len 8; hex 73757072656d756d; asc supremum;;
*** WE ROLL BACK TRANSACTION (2)
------------
How should i interpret this and why did deadlock occur?
The code used is :
Integer generatedId = experimentDAO.add(experimentQO);
......
for..
entitiesDAO.add(entitiesQO);
....
ExperimentQO experimentQO = experimentDAO.get(generatedId);
Exception occurs while adding the entity.
What I see is:
Trx #1 is waiting for an X mode insert intention lock (a kind of gap lock) on the ENTITIES_EXPERIMENT_ID index.
Trx #2 holds an S lock on the ENTITIES_EXPERIMENT_ID index, which is blocking Trx #1
Trx #2 is also waiting for an insert intention lock on the ENTITIES_EXPERIMENT_ID index.
We might assume Trx #1 is also holding an S lock on the same index. S locks are shared, so multiple transactions can acquire S locks on the same row (or gap) concurrently.
If both transactions acquired S locks first, and then both tried to request X locks, then they would enter into a situation where both were waiting on the other one, with no way to break the deadlock.
It's possible that both INSERT statements acquired the S locks as a first step. Or it's possible that you did some other queries that acquire S locks in the same transaction prior to the INSERTs, so both transactions are still holding their respective S locks.
You haven't shown the table definition, so there might be some foreign key constraints, that would cause S locks to be acquired for rows referenced indirectly.
I found below deadlock in "Show engine innodb status" on myql 8.0.11.
As per my understanding both queries should lock only one row (the primary key user_id which is different for both queries). However the second query "*** (2) HOLDS THE LOCK(S): "RECORD LOCKS space id 5461 page no 76054 n bits 96 index PRIMARY of tableuser"`
and First query is waiting to acquire same lock. I did not understand why? even when both lock statement say "locks rec but not gap" which means both are locking only individual records (which should have been their primary key user_id )
Would like to know is my understanding (as explained above) correct? If yes then how to explain the below logs?
*** (1) TRANSACTION:
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
update `user` set `user`.`xxxx` = 1 where ( user_id = 4939334)
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5461 page no 76054 n bits 96 index PRIMARY of table `user` trx id 5385693398 lock_mode X locks rec but not gap waiting
Record lock, heap no 24 PHYSICAL RECORD: n_fields 20; compact format; info bits 0
*** (2) TRANSACTION:
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
update `user` set `user`.`xxxx` = 1 where ( user_id = 4917613)
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 5461 page no 76054 n bits 96 index PRIMARY of table `user` trx id 5385693399 lock_mode X locks rec but not gap
Record lock, heap no 24 PHYSICAL RECORD: n_fields 20; compact format; info bits 0
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 5461 page no 63136 n bits 88 index PRIMARY of table `user` trx id 5385693399 lock_mode X locks rec but not gap waiting
Record lock, heap no 19 PHYSICAL RECORD: n_fields 20; compact format; info bits 0
As I know, innoDB use mechanism of consistent non blocking read,
so every transaction works with its own snapshot.
it is told also in official documentation
A consistent read does not set any locks on the tables it accesses, and therefore other sessions are free to modify those tables at the same time a consistent read is being performed on the table.
But I unexpectedly faced with behavior when classic 'read/update' deadlock appears:
Isolation level REPEATABLE READ (also is reproduced with READ COMMITTED)
Transaction 1 reads row (NOT lock in share mode).
Transaction 2 reads the same row ( ALSO NOT lock in share mode).
then
Transaction 1 tries to update this row.
Transaction 2 also tries to update this row.
After last step, innoDB detects deadlock (there is LATEST DETECTED DEADLOCK below):
----------------
2017-03-31 16:07:03 0x1f58
*** (1) TRANSACTION:
TRANSACTION 413412, ACTIVE 20 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 9 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 3
MySQL thread id 33, OS thread handle 8148, query id 102005 localhost 127.0.0.1 root updating
/* update Order */ update `Order` set ... <fields to update>
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413412 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
*** (2) TRANSACTION:
TRANSACTION 413413, ACTIVE 11 sec starting index read
mysql tables in use 1, locked 1
9 lock struct(s), heap size 1136, 6 row lock(s), undo log entries 3
MySQL thread id 28, OS thread handle 8024, query id 102008 localhost 127.0.0.1 root updating
/* update Order */ update `Order` set ...<fields to update>
*** (2) **HOLDS THE LOCK(S):**
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 2151 page no 709 n bits 88 index PRIMARY of table `ooapp2`.`order` trx id 413413 lock_mode X locks rec but not gap waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 54; compact format; info bits 0
*** WE ROLL BACK TRANSACTION (2)
I can't understand, what happens, why Transaction 2
HOLDS THE LOCK(S)
so if innoDB nevertheless not use Consistent Read with snapshot and sets S-locks
this does not correspond to the fact that is written in official manual.
Don't do that. If you might be updating a row, but meanwhile need the value, use SELECT ... FOR UPDATE;. Just do that, and forget about tx_isolation. Normally, this will turn a Deadlock into a delay. (See innodb_lock_wait_timeout, which defaults to an over-generous 50 seconds.)
Also, when you do get a Deadlock, re-run the entire transaction. Deadlocks will happen no matter how hard you try to avoid them.
I went through MySQL logs and found the reason for deadlock
1st thread is trying to execute below query. Which is waiting for thread 2.
UPDATE M_SAMP SET FLAG=0 WHERE M_ID IN (SELECT M_ID FROM MM_RVW_SAMP WHERE TARGET_M_ID IN(19))
The result of inner query (SELECT M_ID FROM MM_RVW_SAMP WHERE TARGET_M_ID IN(19)) is M_ID = 3562.
2nd thread is executing below query.
DELETE FROM M_SAMP WHERE M_ID=3455
There is no foreign key relation defined in M_SAMP and MM_RVW_SAMP tables. And M_ID is primary key of M_SAMP table. And engine is InnoDB. And this issue is repeating.
Can any one help me, how locks are granted because of which deadlock is happening?
Logs
------------------------
LATEST DETECTED DEADLOCK
------------------------
2015-02-23 10:52:28 de8
*** (1) TRANSACTION:
TRANSACTION 13275344, ACTIVE 0 sec fetching rows
mysql tables in use 2, locked 2
LOCK WAIT 25 lock struct(s), heap size 2408, 1394 row lock(s), undo log entries 1
MySQL thread id 1455, OS thread handle 0x11ac, query id 39660 xyz 192.168.1.108 userName Sending data
UPDATE M_SAMP SET FLAG=0 WHERE M_ID IN (SELECT M_ID FROM MM_RVW_SAMP WHERE TARGET_M_ID IN(19))
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 61569 page no 65 n bits 176 index `PRIMARY` of table `dbName`.`m_samp` trx id 13275344 lock_mode X waiting
Record lock, heap no 3 PHYSICAL RECORD: n_fields 29; compact format; info bits 0
*** (2) TRANSACTION:
TRANSACTION 13275335, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
254 lock struct(s), heap size 27512, 21595 row lock(s), undo log entries 7
MySQL thread id 1458, OS thread handle 0xde8, query id 39664 xyz 192.168.1.108 userName updating
DELETE FROM M_SAMP WHERE M_ID=3455
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 61569 page no 65 n bits 176 index `PRIMARY` of table `dbName`.`m_samp` trx id 13275335 lock mode S locks rec but not gap
Record lock, heap no 3 PHYSICAL RECORD: n_fields 29; compact format; info bits 0
Thank you.
The answer to my question is given here (on dba.stackexchange) by #jynus.
Now I am using below update query.
UPDATE M_SAMP M
JOIN MM_RVW_SAMP MM
ON M.M_ID = MM. M_ID
SET M.FLAG = 1
WHERE MM.TARGET_M_ID = 19;