一个大兄弟的生产大概代码
// 从数据库拿点特定状态的数据
List<X> bosPaymentBills = pageQueryBosPaymentBill(beginTime,endTime, PushStatusEnum.NO_PUSH.getCode(),startId,pageSize);
for (X bosPaymentBill : bosPaymentBills ) {
//加个锁
String key = RedisConst.PAYMENT_BILL_KING_DEE_PUSH_KEY + bosPaymentBill.getBillNo();
try {
RLock lock = redissonClient.getLock(key);
if (lock.tryLock()) {
BosPaymentBill bill = bosPaymentBillMapper.selectByPrimaryKey(bosPaymentBill.getId());
//校验一下 这个单子的状态还对不对
if(Objects.equals(bill.getPushState(), CommonConstant.SYS_TWO)){
continue;
}
//todo 做点啥事
bosPaymentBill.setBosId(Long.valueOf(bosId));
bosPaymentBill.setPushState(2);
}
} catch (Exception e) {
// 做事出现点问题,插个工单 进行处理
WorkSheet workSheet = new WorkSheet(WorkTypeEnum.PAYMENT_BILL_KING_DEE_PUSH.getCode(), JSON.toJSONString(bosPaymentBill), null, null,
WorkTypeEnum.RECEIVE_BILL_KING_DEE_PUSH.getValue(), null, StringUtils.substring(e.getMessage(), 0, 200));
workSheetService.saveWorkSheet(workSheet);
} finally {
// 更改状态 这是本次出现问题的重点
bosPaymentBillMapper.updateByPrimaryKeySelective(bosPaymentBill);
RLock lock = redissonClient.getLock(key);
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}
生产出现问题了,这段代码 在线程比较多的时候会不断地重复插入工单,短短几天就查了几十万的数据
原因
多个线程同时拉到同一条数据,都来获取锁,有一个tryLock获取到了,进行任务处理,更改状态处理成功。但是身后还有一堆狗东西线程 没有获取到,tryLock 返回false,最终跑到finally 执行,导致状态又被改回待执行状态
这样子,又会有线程拉取到这条数据,再次执行。
由于第三方业务系统,并不会自己检查执行返回成功,会给返回特定的报错,我们并没有处理这种情况,不断更新为执行失败,插入工单