记一次线上数据库死锁

        最近,线上订单库老出现报错,通过elk看是是死锁导致数据库回滚了,哲哥那拿来的数据库死锁日志如下:

*** (1) TRANSACTION:
TRANSACTION 728240667, ACTIVE 0 sec starting index read
mysql tables in use 1, locked 1
LOCK WAIT 5 lock struct(s), heap size 1136, 3 row lock(s), undo log entries 1
MySQL thread id 135270358, OS thread handle 140267696391936, query id 2140927486 192.168.1.250 clx updating
update order_contract set goods_required_amount= goods_required_amount-49 where contract_no = ''
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1584 page no 53 n bits 168 index idx_orderContract_contractNo of table `order_service`.`order_contract` trx id 728240667 lock_mode X waiting
Record lock, heap no 27 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 15; hex 585947533230323130313233303031; asc XYGS20210123001;;
 1: len 4; hex 800019a9; asc     ;;

*** (2) TRANSACTION:
TRANSACTION 728240665, ACTIVE 0 sec fetching rows
mysql tables in use 1, locked 1
1314 lock struct(s), heap size 139472, 6469 row lock(s), undo log entries 3230
MySQL thread id 135268737, OS thread handle 140268200789760, query id 2140927480 192.168.1.225 clx updating
update order_info set goods_residue=goods_residue-49.0,modified_time=SYSDATE() where order_no<>'' and contract_no=''
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1584 page no 53 n bits 168 index idx_orderContract_contractNo of table `order_service`.`order_contract` trx id 728240665 lock_mode X
Record lock, heap no 27 PHYSICAL RECORD: n_fields 2; compact format; info bits 0
 0: len 15; hex 585947533230323130313233303031; asc XYGS20210123001;;
 1: len 4; hex 800019a9; asc     ;;

*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1583 page no 10958 n bits 96 index PRIMARY of table `order_service`.`order_info` trx id 728240665 lock_mode X locks rec but not gap waiting
Record lock, heap no 10 PHYSICAL RECORD: n_fields 109; compact format; info bits 0
0: len 4; hex 800368f8; asc   h ;;
 1: len 6; hex 00002b68121b; asc   +h  ;;
 2: len 7; hex 4a000080361df1; asc J   6  ;;
 3: len 4; hex 8000137f; asc     ;;
 4: len 4; hex 80000659; asc    Y;;
 5: len 1; hex 82; asc  ;;
 6: len 1; hex 81; asc  ;;
 7: len 1; hex 82; asc  ;;
 8: len 6; hex e7a59ee8bebe; asc       ;;
 9: len 12; hex e7a5a5e5ae87e585ace58fb8; asc             ;;
(以下省略...)

*** WE ROLL BACK TRANSACTION (1)

        定位到相应的代码位置后,发生死锁时的代码如下:

if (flag.abs().compareTo(new BigDecimal(0)) == 1) {
        
            int order = orderInfoDao.updateXXX(XXX, XXX, 0, XXX);
            if (!StringUtils.isEmpty(CCC)) {
                OrderContractDTO orderContractDTO = AAA;
                if (orderContractDTO == null) {
                    throw new Exception();
                } else {
                    if (BBB == 1) {
                        orderInfoDao.updateYYY(YYY, YYY, YYY);
                        orderContractDao.updateYYY(YYY, flag);
                    }
                }
            }
    }
 /** 费用调整 end*/
 int updateId = orderChildDao.updateZZZ(ZZZ);

          这是一个装车接口,和同事一起分析了下这个代码,orderInfoDao和orderInfoDao顺序本来应该是这样的,但是在别的方法有一个顺序是反过来的,两个方法一起执行就出问题了

        后头的解决方法是修改代码,修改orderInfoDao和orderInfoDao的执行顺序应该就可以了。

        另外,下面id为1、2这两行是事务ID和回滚指针

 0: len 4; hex 800368f8; asc   h ;;
 1: len 6; hex 00002b68121b; asc   +h  ;;
 2: len 7; hex 4a000080361df1; asc J   6  ;;

对于Innodb表中的行每一行包括:

6字节的事务ID(DB_TRX_ID)字段: 用来标识最近一次对本行记录做修改(INSERT|UPDATE)的事务的标识符, 即最后一次修改(INSERT|UPDATE)本行记录的事务id。

7字节的回滚指针(DB_ROLL_PTR)字段: 指写入回滚段(ROLLBACK segment)的 UNDO LOG record (撤销日志记录记录)。

如果一行记录被更新, 则 UNDO LOG record 包含 '重建该行记录被更新之前内容' 所必须的信息。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值