原理
redis设置一个key和value,如果存在则获取锁失败,不存在则获取锁成功处理业务,业务处理完成后删除这条数据,可以带个失效时间。
代码
public void handleInvoice(SubmitInvoiceRpcReq req) throws Exception { boolean isAccess = false; String invoiceKey = String.format(ApiRedisKey.AGENT_WITHDRAW_INVOICE, req.getBaseUserId()); try { isAccess = redisTemplate.setIfAbsent(invoiceKey, "1", 60); JlpayAssert.isTrue(isAccess, "正在处理,稍后再试"); //批处理ID(时间戳+用户ID) String batchNo = System.currentTimeMillis() + String.format("%010d", req.getBaseUserId()); InvoiceVo invoiceVo = new InvoiceVo(); invoiceVo.setBatchNo(batchNo); invoiceVo.setLicenseNo(getLicenseNo(req.getBaseUserId())); HashMap<String, String> channelMap = getChannelMap(); invoiceService.saveSubmitInvoice(req, channelMap, invoiceVo); FixedThreadPoolUtil.INSTANCE.execute(() -> { log.info("提现开票异步任务--开始"); List<WithdrawInvoice> withdrawInvoiceList = invoiceService.getWithdrawInvoiceList(batchNo); if (CollectionUtils.isEmpty(withdrawInvoiceList)) { return; } invoiceService.handleSubmitInvoice(withdrawInvoiceList); withdrawInvoiceList.stream().forEach(withdrawInvoice -> { InvoiceVo vo = makeupInvoiceVo(withdrawInvoice); sendInvoiceEmail(vo, withdrawInvoice); }); log.info("提现开票异步任务--结束"); }); } finally { if (isAccess) { redisTemplate.delete(invoiceKey); } } }
锁失效原因
1. 删除锁之前发生异常
client1 获取到锁A,执行业务操作,这个时候服务发生异常,没有删除锁,导致别人无法操作。
方案: 设置过期时间
2. 过期时间到了,业务没执行完
client1 获取到锁A设置失效时间为十秒,执行业务操作花了20秒才处理完,但是锁已经不在了。
方案:可以把失效时间设置长点,但会影响性能
Redission架构
使用Lua脚本对redis进行加锁操作,确保业务执行的原子性。
看门狗会每隔10s检查客户端是否还持有锁,如果还持有就会延迟key的生存时间。
参考:https://www.cnblogs.com/AnXinliang/p/10019389.html
https://baijiahao.baidu.com/s?id=1730716661153081344&wfr=spider&for=pc
标签:String,--,invoiceVo,req,redis,isAccess,分布式 From: https://www.cnblogs.com/zhougongjin/p/17165798.html