Batch update deadlock problem

Problem Description:

An error occurs when multiple phenomena are updated in batches, and Mysql reports Deadlock found when trying to get lock; try restarting transaction

problem analysis:

There are two main reasons for Mysql deadlock

- Usually when using insert, update, delete and other operations, the database will lock the table. Index conditions need to be added to the condition field to convert table locks into row-level locks and reduce data locks.

- The second is that there is a row-level lock in the database ( InnoDB's row lock is a lock added to the index, not a lock added to the record, and the index cannot be invalidated, otherwise it will be upgraded from a row lock to a table lock), the row lock will be First lock the non-primary key index and then lock the primary key index. Therefore, when the update statement operates on a non-primary key index, not only will the row record be locked, but the non-primary key index will also be locked. Thus occupying resources and causing deadlock.

Query the database deadlock log:

show engine innodb status\G (only for reference instance analysis)

=====================================
2023-06-20 14:46:28 0x7f732fcff700 INNODB MONITOR OUTPUT # 查询死锁日志的时间
=====================================
Per second averages calculated from the last 37 seconds
-----------------
BACKGROUND THREAD
-----------------
srv_master_thread loops: 609 srv_active, 0 srv_shutdown, 23969851 srv_idle
srv_master_thread log flush and writes: 0
----------
SEMAPHORES
----------
OS WAIT ARRAY INFO: reservation count 100
OS WAIT ARRAY INFO: signal count 98
RW-shared spins 0, rounds 0, OS waits 0
RW-excl spins 29, rounds 870, OS waits 25
RW-sx spins 1, rounds 30, OS waits 0
Spin rounds per wait: 0.00 RW-shared, 30.00 RW-excl, 30.00 RW-sx
------------------------
LATEST DETECTED DEADLOCK # 最近一次死锁记录
------------------------
2023-06-20 14:46:15 0x7f7350cf3700
*** (1) TRANSACTION:
TRANSACTION 10298, ACTIVE 11 sec starting index read
# 事务id=10298活跃11秒,正在使用索引读取数据行
mysql tables in use 1, locked 1
# 事务正在使用1个表,涉及锁的表1个
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
# 等待3把锁,占用内存1136字节,涉及2行记录,undo log 记录事务已经更新了1条聚集索引记录
MySQL thread id 7623, OS thread handle 140132789073664, query id 6006191 127.0.0.1 root updating
# 这行表示事务的线程信息,操作系统句柄信息、连接来源、用户
update medicine_control set current_count=1 where id='2'
# 死锁涉及的sql语句
*** (1) HOLDS THE LOCK(S): #事务持有的锁
RECORD LOCKS space id 55 page no 4 n bits 88 index PRIMARY of table `jeecg-boot`.`medicine_control` trx id 10298 lock_mode X locks rec but not gap
Record lock, heap no 21 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
# 事务持有的是表`medicine_control`的record lock(记录锁/行锁),空间id是55,页码4,88位处。锁在表的主键PRIMARY 上,是一个X(独占)锁,但不是间隔锁。n_fields表示记录有12列
 0: len 1; hex 31; asc 1;;
 1: len 6; hex 00000000283a; asc     (:;;
 2: len 7; hex 020000012510db; asc     %  ;;
 3: len 6; hex e5a5b6e5a5b6; asc       ;;
 4: len 12; hex e79b98e5b0bce8a5bfe69e97; asc             ;;
 5: len 4; hex 80000001; asc     ;;
 6: len 4; hex 80000005; asc     ;;
 7: len 4; hex 80000000; asc     ;;
 8: len 5; hex 6a65656367; asc jeecg;;
 9: len 5; hex 99a60eadf7; asc      ;;
 10: len 3; hex 6a6f62; asc job;;
 11: len 5; hex 99a75e0780; asc   ^  ;;
 # 打印的记录信息,asc表示接下来要打印出记录里面的可打印字符,不可打印用空格表示。hex表示16进制
 
*** (1) WAITING FOR THIS LOCK TO BE GRANTED: # 事务等待的锁
RECORD LOCKS space id 55 page no 4 n bits 88 index PRIMARY of table `jeecg-boot`.`medicine_control` trx id 10298 lock_mode X locks rec but not gap waiting
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
# 事务等待的锁是表`medicine_control`的record lock(记录锁/行锁),空间id是55,页码4,88位处。锁在表的主键PRIMARY 上,是一个X(独占)锁,但不是间隔锁。n_fields表示记录有12列
 0: len 1; hex 32; asc 2;;
 1: len 6; hex 00000000283b; asc     (;;;
 2: len 7; hex 01000002012bd8; asc      + ;;
 3: len 6; hex e788b7e788b7; asc       ;;
 4: len 6; hex e69f90e69f90; asc       ;;
 5: len 4; hex 80000002; asc     ;;
 6: len 4; hex 80000002; asc     ;;
 7: len 4; hex 80000000; asc     ;;
 8: len 5; hex 6c6979616e; asc liyan;;
 9: len 5; hex 99a67b3730; asc   {70;;
 10: len 3; hex 6a6f62; asc job;;
 11: len 5; hex 99a75e0780; asc   ^  ;;
 
 
*** (2) TRANSACTION: #事务2
TRANSACTION 10299, ACTIVE 7 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 1
MySQL thread id 7625, OS thread handle 140133576603392, query id 6006195 127.0.0.1 root updating
update medicine_control set current_count=2 where id='1'
 
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 55 page no 4 n bits 88 index PRIMARY of table `jeecg-boot`.`medicine_control` trx id 10299 lock_mode X locks rec but not gap
Record lock, heap no 4 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 1; hex 32; asc 2;;
 1: len 6; hex 00000000283b; asc     (;;;
 2: len 7; hex 01000002012bd8; asc      + ;;
 3: len 6; hex e788b7e788b7; asc       ;;
 4: len 6; hex e69f90e69f90; asc       ;;
 5: len 4; hex 80000002; asc     ;;
 6: len 4; hex 80000002; asc     ;;
 7: len 4; hex 80000000; asc     ;;
 8: len 5; hex 6c6979616e; asc liyan;;
 9: len 5; hex 99a67b3730; asc   {70;;
 10: len 3; hex 6a6f62; asc job;;
 11: len 5; hex 99a75e0780; asc   ^  ;;
 
 
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 55 page no 4 n bits 88 index PRIMARY of table `jeecg-boot`.`medicine_control` trx id 10299 lock_mode X locks rec but not gap waiting
Record lock, heap no 21 PHYSICAL RECORD: n_fields 12; compact format; info bits 0
 0: len 1; hex 31; asc 1;;
 1: len 6; hex 00000000283a; asc     (:;;
 2: len 7; hex 020000012510db; asc     %  ;;
 3: len 6; hex e5a5b6e5a5b6; asc       ;;
 4: len 12; hex e79b98e5b0bce8a5bfe69e97; asc             ;;
 5: len 4; hex 80000001; asc     ;;
 6: len 4; hex 80000005; asc     ;;
 7: len 4; hex 80000000; asc     ;;
 8: len 5; hex 6a65656367; asc jeecg;;
 9: len 5; hex 99a60eadf7; asc      ;;
 10: len 3; hex 6a6f62; asc job;;
 11: len 5; hex 99a75e0780; asc   ^  ;;
 
*** WE ROLL BACK TRANSACTION (2) # 事务处理结果:事务2回滚
------------
TRANSACTIONS # 当前SESSION和事务,多数的SESSION下的事务都没开始状态
------------
Trx id counter 10301
Purge done for trx's n:o < 10301 undo n:o < 0 state: running but idle
History list length 61
LIST OF TRANSACTIONS FOR EACH SESSION:
---TRANSACTION 421608706154464, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706153592, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706152720, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706151848, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706150976, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706150104, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706148360, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706147488, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706146616, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706145744, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706144872, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 421608706144000, not started
0 lock struct(s), heap size 1136, 0 row lock(s)
---TRANSACTION 10298, ACTIVE 24 sec
3 lock struct(s), heap size 1136, 2 row lock(s), undo log entries 2
MySQL thread id 7623, OS thread handle 140132789073664, query id 6006198 127.0.0.1 root
--------
FILE I/O
--------
I/O thread 0 state: waiting for completed aio requests (insert buffer thread)
I/O thread 1 state: waiting for completed aio requests (log thread)
I/O thread 2 state: waiting for completed aio requests (read thread)
I/O thread 3 state: waiting for completed aio requests (read thread)
I/O thread 4 state: waiting for completed aio requests (read thread)
I/O thread 5 state: waiting for completed aio requests (read thread)
I/O thread 6 state: waiting for completed aio requests (write thread)
I/O thread 7 state: waiting for completed aio requests (write thread)
I/O thread 8 state: waiting for completed aio requests (write thread)
I/O thread 9 state: waiting for completed aio requests (write thread)
Pending normal aio reads: [0, 0, 0, 0] , aio writes: [0, 0, 0, 0] ,
 ibuf aio reads:, log i/o's:, sync i/o's:
Pending flushes (fsync) log: 0; buffer pool: 0
2048 OS file reads, 24777 OS file writes, 11472 OS fsyncs
0.00 reads/s, 0 avg bytes/read, 0.59 writes/s, 0.54 fsyncs/s
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 3 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 2 buffer(s)
Hash table size 34679, node heap has 5 buffer(s)
0.00 hash searches/s, 0.27 non-hash searches/s
---
LOG
---
Log sequence number          2246453180
Log buffer assigned up to    2246453180
Log buffer completed up to   2246453180
Log written up to            2246453180
Log flushed up to            2246453180
Added dirty pages up to      2246453180
Pages flushed up to          2246453180
Last checkpoint at           2246453180
9242 log i/o's done, 0.14 log i/o's/second
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 137363456
Dictionary memory allocated 835752
Buffer pool size   8192
Free buffers       6046
Database pages     2131
Old database pages 788
Modified db pages  0
Pending reads      0
Pending writes: LRU 0, flush list 0, single page 0
Pages made young 0, not young 0
0.00 youngs/s, 0.00 non-youngs/s
Pages read 1923, created 208, written 13739
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
Buffer pool hit rate 1000 / 1000, young-making rate 0 / 1000 not 0 / 1000
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: 2131, unzip_LRU len: 0
I/O sum[0]:cur[0], unzip sum[0]:cur[0]
--------------
ROW OPERATIONS
--------------
0 queries inside InnoDB, 0 queries in queue
0 read views open inside InnoDB
Process ID=920, Main thread ID=140133220153088 , state=sleeping
Number of rows inserted 416, updated 2599, deleted 440, read 821958
0.00 inserts/s, 0.08 updates/s, 0.00 deletes/s, 0.11 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

By analyzing the database deadlock log, it can be found that the deadlock is caused by two update statements believed to snatch resources. My problem is actually similar, mainly in two points:

1. My record lock is locked on a non-primary key index, resulting in a resource conflict. Therefore, it is better to set the non-primary key index settings on fields that are not frequently updated, otherwise all records related to the index will be locked for you. It is easy to cause deadlock problem.

2. Ordinary updates will not cause serious table locks, and the speed is relatively fast. The main reason is that my update operation is nested in a very long transaction. If the transaction is not committed, the acquired lock will not be released, and the deadlock is caused by long-term occupation of resources.

problem solved:

The update statement does not operate on non-primary key indexes to avoid locking more resources.

Guess you like

Origin blog.csdn.net/weixin_49363689/article/details/131300539
Recommended