场景1
订单中心接收MQ下发出库信息
(中台接收云POS的出库信息BMS125,写到库存移动单据表)
存在问题
MQ重复下发,导致重复消费
解决方案
redis分布式锁
重复纬key
1,MQ key
2,下发内容,如订单号
具体处理方案
@Autowired private ValueOperations<String, String> valueOperations;
1,通过key获取value
String value = (String)this.valueOperations.get(key);
2,存在,return,即已消费,流程结束
3,不存在,设置key,过期时间10天
redisUtils.set(key, value,expired);
4,执行业务逻辑
5,在catch中删除key,释放锁
} catch (Exception e) { redisUtils.delete(key); log.error(""); throw new OrderCenterException(""); }
思考,以上方案为了解决什么问题
以上解决方案为了解决什么问题,应该就是避免重复消费的问题,只要正常消费一次后(无异常,不走catch),后面10天内,再下发相同的订单,不再处理。
关于过期时间10天,为什么10天,这个具体时间,根据实际业务场景定的。10天以后,就不可能再次下发,或者即便下发了,继续处理,不管是否重复的问题了。
分布式锁漏洞
1,加锁与设置过期时间非原子操作,可能加锁失败,导致永不过期。代码如下
public void set(String key, Object value, long expire) { this.valueOperations.set(key, JsonUtils.toJson(value)); if (expire != -1L) { this.expire(key, expire, TimeUnit.SECONDS); } }
2,在catch中释放锁,如果加锁后,服务挂了,导致永不过期
针对以上问题解决方案
1,使用setNX
2,只有通过准备控制过期时间,来自动释放锁了。(注意在finally中释放锁,解决的程序异常时,无法释放锁的问题,这里catch中释放锁刚好解决了异常无法释放锁的问题
redisson
解决了什么问题
1,锁续期问题
场景2
手动创建交车计划单
存在问题
前端重复提交
解决方案
redission
String workOrderNo = reqDTO.getWorkOrderNo(); RLock rLock = redissonClient.getLock(Constant.DELIVERY_PLAN_CREATE_WORK_ORDER_LOCK + workOrderNo); try { boolean isLocked = rLock.tryLock(); if (!isLocked) { throw new LeaseServiceException(ErrConstant.OPERATION_FAILED, "请勿重复提交"); }
// todo业务逻辑
} finally { if (rLock.isLocked() && rLock.isHeldByCurrentThread()) { rLock.unlock(); } }