处理逻辑,为了防止同一个订单,产生并发的问题,这里设置了一个锁,向redis 中加入以订单号为key的键值对,

每次执行订单处理时,会先判断redis 缓存中是否有这个key,

已存在的话,就挂起一段之间,重试5次,

如果在业务逻辑处理完,会删除redis 中的关于该订单的数据

import java.util.ArrayList;
import java.util.List;
import java.util.Set;import org.apache.commons.collections.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;import com.suning.fsp.common.exception.AppException;/*** 一个接一个业务处理模版默认实现<br>* * <p>* 用一个业务处理表记录,在处理前对锁状态进行判断 ,判断逻辑参见{@link #beforeInvoke}方法<br>* * 业务处理表: 业务类型 PK|业务ID PK|方法|创建时间<br>* * */
@Service("redisOneByOneTemplate")
public class RedisOneByOneTemplateImpl implements RedisOneByOneTemplate { /** 业务正在处理中 */public static final String ERROR_BIZ_PROCESSING = "error.biz.processing";/** logger */private static final Logger LOGGER = LoggerFactory.getLogger(RedisOneByOneTemplateImpl.class);private static final String CACHE_PREFIX_KEY = "EPP:FSP:ONEBYONE:CACHE:";private static final Long REDIS_OPT_RES_FAIL = 0L;/*** 并发时循环等待的最大次数*/private static final int REPEAT_MAX_COUNT = 5;@AutowiredRedisOneByOneCacheDao redisOneByOneCacheDao;/*** {@inheritDoc}*/public <T> T execute(OneByOne oneByOne, CallBack<T> callBack) {oneByOne.setDescription(oneByOne.getBizType() + "-" + oneByOne.getBizId() + "-" + oneByOne.getMethod());try {this.beforeInvoke(oneByOne);return callBack.invoke();} finally {this.afterInvoke(oneByOne);}}/*** 查询所有的存在的OneByOne锁* @return OneByOne锁列表*/@Overridepublic List<String> queryAllOneByOne() {Set<String> values = redisOneByOneCacheDao.smembers(CACHE_PREFIX_KEY);return new ArrayList<String>(values);}/*** 清除所有的OneByOne锁*/@Overridepublic void clearOneByOne(List<String> values) {if (CollectionUtils.isNotEmpty(values)) {for (String value : values) {redisOneByOneCacheDao.srem(CACHE_PREFIX_KEY, value);}}}/*** 回调前置* * @param oneByOne 一个接一个处理记录*/private void beforeInvoke(final OneByOne oneByOne) {int count = 0;do {try {oneByOne.setInsertSuccess(true);// 插入处理记录Long addRes = redisOneByOneCacheDao.sadd(CACHE_PREFIX_KEY, oneByOne.getBizType() + "|" + oneByOne.getBizId());if (REDIS_OPT_RES_FAIL == addRes) {oneByOne.setInsertSuccess(false);LOGGER.info(oneByOne.getDescription() + "插入处理记录发生错误!");} } catch (Throwable t) {oneByOne.setInsertSuccess(false);LOGGER.error(oneByOne.getDescription() + "插入处理记录发生异常!t:{}", t);}if (!oneByOne.isInsertSuccess()) {LOGGER.info(oneByOne.getDescription() + "插入处理记录失败!");// 重试次数累加count++;if (count >= REPEAT_MAX_COUNT) {// 如果插入失败,抛出AppExceptionthrow new AppException(ERROR_BIZ_PROCESSING, oneByOne.getDescription() + "业务正在处理中");}// 等待一段时间try {// 每次等待时间拉长Thread.sleep(2000);} catch (InterruptedException e) {LOGGER.info(oneByOne.getDescription() + " occur InterruptedException while wait.");}}}while (!oneByOne.isInsertSuccess());}/*** 回调后置* * @param oneByOne 一个接一个处理记录*/private void afterInvoke(final OneByOne oneByOne) {// 插入失败,不删除处理记录if (!oneByOne.isInsertSuccess()) {return;}try {// 删除处理记录Long res = redisOneByOneCacheDao.srem(CACHE_PREFIX_KEY, oneByOne.getBizType() + "|" + oneByOne.getBizId());if (res > 0) {LOGGER.debug("Remove oneByOne success, the bizType is: {}, the bizId is: {}", oneByOne.getBizType(), oneByOne.getBizId());} else {LOGGER.debug("No value exist in redis, the bizType is: {}, the bizId is: {}", oneByOne.getBizType(), oneByOne.getBizId());}} catch (Throwable t) {LOGGER.error(oneByOne.getDescription() + "删除处理记录失败!t:{}", t);}}
}

callback 接口

public interface CallBack<T> {/*** 调用* @return 结果*/T invoke();}

oneByone类

public class OneByOne {/** 业务类型 */private String bizType;/** 业务ID */private String bizId;/** 方法 */private String method;/** 创建时间 */private Date createTime;private String description;private boolean insertSuccess;/*** 同时最大等待执行的个数(默认为10个)*/private int maxWaitCount = 10;/*** 创建一个接一个处理记录* * @param bizType 业务类型* @param bizId 业务ID* @param method 方法*/public OneByOne(String bizType, String bizId, String method) {this.bizType = bizType;this.bizId = bizId;this.method = method;}/*** 创建一个接一个处理记录* * @param bizType 业务类型* @param bizId 业务ID* @param method 方法* @param maxWaitCount 最大等待数*/public OneByOne(String bizType, String bizId, String method, int maxWaitCount) {this.bizType = bizType;this.bizId = bizId;this.method = method;this.setMaxWaitCount(maxWaitCount);}/*** 获取业务类型* * @return 业务类型*/public String getBizType() {return bizType;}/*** 设置业务类型* * @param bizType 业务类型*/public void setBizType(String bizType) {this.bizType = bizType;}/*** 获取业务ID* * @return 业务ID*/public String getBizId() {return bizId;}/*** 设置业务ID* * @param bizId 业务ID*/public void setBizId(String bizId) {this.bizId = bizId;}/*** 获取方法* * @return 方法*/public String getMethod() {return method;}/*** 设置方法* * @param method 方法*/public void setMethod(String method) {this.method = method;}/*** 获取创建时间* * @return 创建时间*/public Date getCreateTime() {return createTime;}/*** 设置创建时间* * @param createTime 创建时间*/public void setCreateTime(Date createTime) {this.createTime = createTime;}/*** @return the description*/String getDescription() {return description;}/*** @param description the description to set*/void setDescription(String description) {this.description = description;}/*** @return the insertSuccess*/boolean isInsertSuccess() {return insertSuccess;}/*** @param insertSuccess the insertSuccess to set*/void setInsertSuccess(boolean insertSuccess) {this.insertSuccess = insertSuccess;}public void setMaxWaitCount(int maxWaitCount) {this.maxWaitCount = maxWaitCount;}public int getMaxWaitCount() {return maxWaitCount;}
}

使用redis 实现分布式锁,处理并发问题相关推荐

  1. 使用Redis分布式锁处理并发,解决超卖问题

    使用Redis分布式锁处理并发,解决超卖问题 参考文章: (1)使用Redis分布式锁处理并发,解决超卖问题 (2)https://www.cnblogs.com/VitoYi/p/8726070.h ...

  2. SpringBoot 使用 Redis 分布式锁解决并发问题

    问题背景 现在的应用程序架构中,很多服务都是多副本运行,从而保证服务的稳定性.一个服务实例挂了,其他服务依旧可以接收请求.但是服务的多副本运行随之也会引来一些分布式问题,比如某个接口的处理逻辑是这样的 ...

  3. 基于 Redis 实现分布式锁思考

    以下文章来源方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/xuan_lu/article/details/111600302 分布式锁 基于redis实 ...

  4. Redis实现分布式锁的深入探究

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试文章 一.分布式锁简介 锁 是一种用来解决多个执行线程 访问共享资源 错 ...

  5. nx set 怎么实现的原子性_基于Redis的分布式锁实现

    前言 本篇文章主要介绍基于Redis的分布式锁实现到底是怎么一回事,其中参考了许多大佬写的文章,算是对分布式锁做一个总结 分布式锁概览 在多线程的环境下,为了保证一个代码块在同一时间只能由一个线程访问 ...

  6. Zookeeper和Redis实现分布式锁,附我的可靠性分析

    作者:今天你敲代码了吗 链接:https://www.jianshu.com/p/b6953745e341 在分布式系统中,为保证同一时间只有一个客户端可以对共享资源进行操作,需要对共享资源加锁来实现 ...

  7. Redis——由分布式锁造成的重大事故

    作者:浪漫先生 原文:juejin.im/post/6854573212831842311 前言 基于Redis使用分布式锁在当今已经不是什么新鲜事了.本篇文章主要是基于我们实际项目中因为redis分 ...

  8. 每秒上千订单场景下的分布式锁高并发优化实践!

    本文授权转自石杉的架构笔记 背景引入 首先,我们一起来看看这个问题的背景? 前段时间有个朋友在外面面试,然后有一天找我聊说:有一个国内不错的电商公司,面试官给他出了一个场景题: 假如下单时,用分布式锁 ...

  9. 基于Redis的分布式锁和Redlock算法

    来自:后端技术指南针 1 前言 今天开始来和大家一起学习一下Redis实际应用篇,会写几个Redis的常见应用. 在我看来Redis最为典型的应用就是作为分布式缓存系统,其他的一些应用本质上并不是杀手 ...

  10. redis 实现分布式锁

    为什么80%的码农都做不了架构师?>>>    redis 实现分布式锁 伪代码 lock(){if(jedis.setNx("key",timestamp)){ ...

最新文章

  1. python与c语言在语法上的区别-C语言和Python编程先学习哪个
  2. Senparc.Weixin.MP SDK 微信公众平台开发教程(十八):Web代理功能
  3. tcpdump抓取mysql语句
  4. 像小猪佩奇那样生活,需要多少钱?
  5. [深入学习C#]LINQ查询表达式详解(1)——基本语法、使用扩展方法和Lambda表达式简化LINQ查询
  6. 学生成绩abcde怎样划分_7月学考成绩出来啦!
  7. python gmm em算法 2维数据_AI大语音(六)——混合高斯模型(GMM)(深度解析)...
  8. 3使用技巧_盆栽金钱树,平时使用“3个”技巧,叶子稠密、基部冒新芽
  9. Backpropogation反向传播公式推导【李宏毅深度学习版】
  10. 计算机考研高等代数,福大考研经验贴:我的数学考研之路(数学分析和高等代数)...
  11. java 学籍管理系统课程设计_Java课程设计-学籍信息管理系统
  12. dreamweaver cs6 html教程,Dreamweaver cs6安装详细图文教程
  13. 周期性行业是什么意思_周期性股票是什么意思 周期性股票的特征有哪些
  14. 华为机试4.27:公式修正
  15. 基于Halcon学习的车牌识别【一】
  16. 【技法操作】UI界面设计教程,用PS绘制计算器页面
  17. NLP之基于TextCNN的文本情感分类
  18. JAVA--equal、length、Arrays、Static
  19. 一文搞清楚 DNS 的来龙去脉
  20. y yun m_yun是y---un 组成 ,还是y----ün组成

热门文章

  1. 阴阳师服务器延迟,阴阳师百闻牌开服时间推迟,开服延迟补偿领取方式[多图]...
  2. 工程管理,用网页就够了!——Wish3D Earth在线三维地球强势上线
  3. 武汉理工大学计算机专业英语,给大家讲个笑话,武汉理工外语专业400分以上的28人...
  4. wget下载大文件,在某个点卡住了
  5. 比亚迪将自研自动驾驶芯片;工信部:中西部数据中心占比已达37%;特斯拉被要求赔偿顾客11.2万欧元 | 每日大事件...
  6. 天津阿里云代理商:大事件!全国一体化算力调度平台来了,天翼云、华为云、阿里云已接入
  7. java语言 获取本机的ip地址
  8. [转载]你不知道的Trello隐藏生产力提升技巧
  9. 怎么找html代码js的位置,html文件里引用js文件一般放在什么位置才是最适合?
  10. selenium java 1688_1688/阿里巴巴爬虫案例