背景
操作涉及一批数据,如订单,可能存在多个场景下操作,先使用读锁,从redis缓存中获取操作中数据
比如
关闭账单,
发起调账,
线下结算,
合并支付
先判断当前操作的数据,是否在其他地方操作中(在redis set结构中),
存在:提示稍后再操作,业务流程终止。
不存在:把当前操作数据放入redis 缓存中(同时这个动作加写锁),在加写锁的过程中,是不允许其他读锁读取数据的
然后,进行业务逻辑处理
什么把缓存中数据删除呢?
操作完成,删除缓存中数据(同时加写锁)
/**
* 删除操作完成的账单号缓存
*
* @param billNoList
*/
public void removeInOperationBillNoCache(List<String> billNoList) {
log.info("removeInOperationBillNoCache--->billNoList:{}", JSON.toJSONString(billNoList));
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(Constant.LEASE_BILL_IN_OPERATION_KEY);
RLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
billNoList.forEach(billNo -> redisService.srem(Constant.LEASE_BILL_IN_OPERATION_CACHE, billNo));
} finally {
writeLock.unlock();
}
}
判断及读写锁逻辑
/**
* 缓存操作中的账单号
*
* @param billNoList
*/
@SuppressWarnings("unchecked")
public void inOperationBillNoCache(List<String> billNoList) {
log.info("inOperationBillNoCache--->billNoList:{}", JSON.toJSONString(billNoList));
RReadWriteLock readWriteLock = redissonClient.getReadWriteLock(Constant.LEASE_BILL_IN_OPERATION_KEY);
RLock rLock = readWriteLock.readLock();
rLock.lock();
try {
if (redisService.hasKey(Constant.LEASE_BILL_IN_OPERATION_CACHE)) {
Set<String> inOperationBillNoSet = redisService.smembers(Constant.LEASE_BILL_IN_OPERATION_CACHE);
log.info("inOperationBillNoCache--->inOperationBillNoSet:{}", JSON.toJSONString(inOperationBillNoSet));
if (CollectionUtils.isNotEmpty(inOperationBillNoSet)) {
List<String> multipleOperationBillNoList = (List<String>) CollectionUtils.intersection(inOperationBillNoSet, billNoList);
throw new LeaseServiceException(ErrConstant.INVALID_DATAFILED, String.format("账单[%s]存在多人操作,请刷新后重试", String.join(",", multipleOperationBillNoList)));
}
}
} finally {
rLock.unlock();
}
RLock writeLock = readWriteLock.writeLock();
writeLock.lock();
try {
billNoList.forEach(billNo -> redisService.sadd(Constant.LEASE_BILL_IN_OPERATION_CACHE, billNo));
} finally {
writeLock.unlock();
}
}
调用场景
关于缓存数据redis结构选取
set,数据不重复,可以计算交集,判断是否在当前元素中
源码