事物导致的死锁问题分析

先看异常日志

代码:

@Override

@Transactional(propagation = Propagation.REQUIRED, readOnly = false, rollbackFor = RuntimeException.class)

public void updateAuthStatus(Long userId, Integer authType, Integer authStatus) {

    retryNum++;

    try {

        creAuthStatusDao.updateAuthStatus(userId, authType, authStatus);

        int creditNum = creAuthStatusDao.countAuthedCreditNum(userId);

 

        ....

    } catch (Exception e) {

        log.error("updateAuthStatus: exception = {}", e);

    }

}

 

在一个事物中既有update,又有select for update(意向排它锁)

数据库中,有user_id的索引和user_id与auth_type的联合索引

session 1

session 2

begin;

 
 

begin;

update cre_auth_status SET user_id='29507138388754432',auth_type=4,auth_status=2,update_time='2018-11-21 09:32:35.414' WHERE (user_id='29507138388754432' and auth_type=2)

排它锁,因为有单独索引,将锁user_id='29507138388754432'的相关数据表单锁定。

 
 

update cre_auth_status SET user_id='29507138388754432',auth_type=9,auth_status=2,update_time='2018-11-21 09:32:35.414' WHERE (user_id='29507138388754432' and auth_type=9)

排它锁pending

select id, user_id, basic_type, auth_type, auth_status, task_id, auth_time, expire_time, create_time, update_time from cre_auth_status where user_id = '29507138388754432' AND basic_type =3 AND auth_status =2 FOR UPDATE

需要等待user_id='29507138388754432'的数据释放,锁也是处于pending状态,和session2争抢锁资源,进入死锁。

 

Select时,user_id的索引需要锁住了user_id=’ 29507138388754432’的数据,等待session2中的update释放,但是因为session2中的排它锁是pending状态,未commit,锁等待中,进入死锁

select id, user_id, basic_type, auth_type, auth_status, task_id, auth_time, expire_time, create_time, update_time from cre_auth_status where user_id = '29507138388754432' AND basic_type =3 AND auth_status =2 FOR UPDATE

死锁出现异常,事物回滚

拿到锁,正常流程往下走

解决方式:

  1. 将事物放在update里,等待update结束之后,再进行select
  2. 去掉事物,事物在这里属于画蛇添足。

@Override

public void updateAuthStatus(Long userId, Integer authType, Integer authStatus, String operatorGid, int retryNum) {

    retryNum++;

try {

        creAuthStatusDao.updateAuthStatus(userId, authType, authStatus);

        int creditNum = creAuthStatusDao.countAuthedCreditNum(userId);

 

        ....

    } catch (Exception e) {

        log.error("updateAuthStatus: exception = {}", e);

    }

}

 

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值