MySQL 5.5 版本,事物中因为 S 锁,导致后续 update 语句出现死锁,请大佬帮我分析一下

场景:有一个提交订单的操作,在事物执行过程中库存表被操作两次,第一次是select语句,第二次是update,在执行过程中出现了死锁。

事物中包含这个表的操作的两处代码如下:

第一处

MySQL 5.5 版本,事物中因为 S 锁,导致后续 update 语句出现死锁,请大佬帮我分析一下

第二处

MYSQL 5.5版本,事物中因为S锁,导致后续update语句出现死锁,请大佬帮我分析一下
两处代码中有一些判断库存是否足够的逻辑

在并发中出现了死锁的情况,死锁日志附在最后。
因为死锁日志中说有一个事物拥有S锁,但是我并没有在事物的任何地方用 lock in share mode 加锁,有点想不通,google上也没有找到有价值的资料,我所了解到的 select 除非显示指定加锁,否则不会任何锁到查询结果上,那么这个S锁是怎么来的呢?

附录:

  1. show engine InnoDB status 的结果

    =====================================
    200107 20:50:08 INNODB MONITOR OUTPUT
    =====================================
    Per second averages calculated from the last 2 seconds
    -----------------
    BACKGROUND THREAD
    -----------------
    srv_master_thread loops: 1075284 1_second, 1075284 sleeps, 94343 10_second, 139601 background, 139597 flush
    srv_master_thread log flush and writes: 1076095
    ----------
    SEMAPHORES
    ----------
    OS WAIT ARRAY INFO: reservation count 291167, signal count 282874
    Mutex spin waits 186869, rounds 5618225, OS waits 168869
    RW-shared spins 99472, rounds 2984074, OS waits 69671
    RW-excl spins 19063, rounds 1577971, OS waits 47999
    Spin rounds per wait: 30.07 mutex, 30.00 RW-shared, 82.78 RW-excl
    ------------------------
    LATEST DETECTED DEADLOCK
    ------------------------
    200107 11:55:08
    *** (1) TRANSACTION:
    TRANSACTION BA9158, ACTIVE 0 sec starting index read
    mysql tables in use 1, locked 1
    LOCK WAIT 25 lock struct(s), heap size 3112, 47 row lock(s)
    MySQL thread id 285444, OS thread handle 0x7f34240cf700, query id 12333484 *.*.*.* root Updating
    update t_inventory
                set out_count = convert(1748.000000, decimal(19, 0)), out_price = 16.933352, out_money = 29599.500000,
                    balance_count = convert(380.000000, decimal(19, 0)), balance_money = 6270.000000
                where warehouse_id = '9BC7C41D-B5C1-11E9-ACCF-00163E02BF40' and goods_id = '11338'
    *** (1) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 0 page no 18850 n bits 800 index `t_inventory_goods_id_index` of table `cod_erp`.`t_inventory` trx id BA9158 lock_mode X waiting
    Record lock, heap no 459 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
     0: len 5; hex 3131333338; asc 11338;;
     1: len 8; hex 8000000000000cac; asc         ;;
    
    *** (2) TRANSACTION:
    TRANSACTION BA915B, ACTIVE 0 sec starting index read
    mysql tables in use 1, locked 1
    25 lock struct(s), heap size 3112, 47 row lock(s)
    MySQL thread id 285438, OS thread handle 0x7f3418c0e700, query id 12333485 *.*.*.* root Updating
    update t_inventory
                set out_count = convert(1748.000000, decimal(19, 0)), out_price = 16.933352, out_money = 29599.500000,
                    balance_count = convert(380.000000, decimal(19, 0)), balance_money = 6270.000000
                where warehouse_id = '9BC7C41D-B5C1-11E9-ACCF-00163E02BF40' and goods_id = '11338'
    *** (2) HOLDS THE LOCK(S):
    RECORD LOCKS space id 0 page no 18850 n bits 800 index `t_inventory_goods_id_index` of table `cod_erp`.`t_inventory` trx id BA915B lock mode S
    Record lock, heap no 459 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
     0: len 5; hex 3131333338; asc 11338;;
     1: len 8; hex 8000000000000cac; asc         ;;
    
    *** (2) WAITING FOR THIS LOCK TO BE GRANTED:
    RECORD LOCKS space id 0 page no 18850 n bits 800 index `t_inventory_goods_id_index` of table `cod_erp`.`t_inventory` trx id BA915B lock_mode X waiting
    Record lock, heap no 459 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
     0: len 5; hex 3131333338; asc 11338;;
     1: len 8; hex 8000000000000cac; asc         ;;
    
    *** WE ROLL BACK TRANSACTION (2)
    ------------
    TRANSACTIONS
    ------------
    Trx id counter BB6AD9
    Purge done for trx's n:o < BB6ACB undo n:o < 0
    History list length 1252
    LIST OF TRANSACTIONS FOR EACH SESSION:
    ---TRANSACTION 0, not started
    MySQL thread id 293700, OS thread handle 0x7f3424192700, query id 12702737 *.*.*.* root
    ---TRANSACTION 0, not started
    MySQL thread id 293699, OS thread handle 0x7f34240cf700, query id 12702824 *.*.*.* root
    ---TRANSACTION BB6AD1, not started
    MySQL thread id 293698, OS thread handle 0x7f34156c2700, query id 12702908 *.*.*.* root
    show ENGINE INNODB status
    --------
    FILE I/O
    --------
    I/O thread 0 state: waiting for i/o request (insert buffer thread)
    I/O thread 1 state: waiting for i/o request (log thread)
    I/O thread 2 state: waiting for i/o request (read thread)
    I/O thread 3 state: waiting for i/o request (read thread)
    I/O thread 4 state: waiting for i/o request (read thread)
    I/O thread 5 state: waiting for i/o request (read thread)
    I/O thread 6 state: waiting for i/o request (write thread)
    I/O thread 7 state: waiting for i/o request (write thread)
    I/O thread 8 state: waiting for i/o request (write thread)
    I/O thread 9 state: waiting for i/o request (write thread)
    Pending normal aio reads: 0 [0, 0, 0, 0] , aio writes: 0 [0, 0, 0, 0] ,
     ibuf aio reads: 0, log i/o's: 0, sync i/o's: 0
    Pending flushes (fsync) log: 0; buffer pool: 0
    254575643 OS file reads, 2626664 OS file writes, 1560458 OS fsyncs
    0.00 reads/s, 0 avg bytes/read, 0.00 writes/s, 0.00 fsyncs/s
    -------------------------------------
    INSERT BUFFER AND ADAPTIVE HASH INDEX
    -------------------------------------
    Ibuf: size 1, free list len 12, seg size 14, 218732 merges
    merged operations:
     insert 453566, delete mark 1980934, delete 2352
    discarded operations:
     insert 0, delete mark 0, delete 0
    Hash table size 34679, node heap has 22 buffer(s)
    0.00 hash searches/s, 0.00 non-hash searches/s
    ---
    LOG
    ---
    Log sequence number 14929779885
    Log flushed up to   14929779885
    Last checkpoint at  14929779885
    0 pending log writes, 0 pending chkp writes
    1414978 log i/o's done, 0.00 log i/o's/second
    ----------------------
    BUFFER POOL AND MEMORY
    ----------------------
    Total memory allocated 17170432; in additional pool allocated 0
    Dictionary memory allocated 1070678
    Buffer pool size   1024
    Free buffers       1
    Database pages     1001
    Old database pages 349
    Modified db pages  0
    Pending reads 0
    Pending writes: LRU 0, flush list 0, single page 0
    Pages made young 348119979, not young 0
    0.00 youngs/s, 0.00 non-youngs/s
    Pages read 340194818, created 67746, written 1560724
    0.00 reads/s, 0.00 creates/s, 0.00 writes/s
    No buffer pool page gets since the last printout
    Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
    LRU len: 1001, unzip_LRU len: 0
    I/O sum[5075]:cur[0], unzip sum[0]:cur[0]
    --------------
    ROW OPERATIONS
    --------------
    0 queries inside InnoDB, 0 queries in queue
    1 read views open inside InnoDB
    Main thread process no. 2731, id 139861685458688, state: waiting for server activity
    Number of rows inserted 5273253, updated 6312884, deleted 4865078, read 17337326011
    0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
    ----------------------------
    END OF INNODB MONITOR OUTPUT
    ============================
讨论数量: 3
TimJuly

select for update就是在拿锁,把for update去掉就不会死锁了。

4年前 评论
liuwq (楼主) 4年前
liuwq (楼主) 4年前

有没有可能你select语句是表锁,导致update等待?

3年前 评论

这个问题我后来没有再深究,给加了一个文件锁,不同进程到这里排队就行了,本来就是异步任务,感觉研究并发问题没有必要,哈哈

3年前 评论

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!