临文乍了了,彻卷兀若无。这篇文章主要讲述简单介绍redis分布式锁解决表单重复提交的问题相关的知识,希望能为你提供帮助。
在系统中,有些接口如果重复提交,可能会造成脏数据或者其他的严重的问题,所以我们一般会对与数据库有交互的接口进行重复处理。本文就详细的介绍一下redis分布式锁解决表单重复提交,感兴趣的可以了解一下 |
使用redis的setnx和getset??命令??解决表单重复提交的问题。
1.引入redis依赖和aop依赖
org.springframework.bootspring-boot-starter-redis1.3.8.RELEASEorg.springframework.bootspring-boot-starter-aop
2.编写加锁和解锁的方法。
/*** @author wangbin* @description redis分布式锁* @date 2019年09月20日*/ @Component public class RedisLock {private final Logger logger = LoggerFactory.getLogger(RedisLock.class); @Autowiredprivate StringRedisTemplate redisTemplate; /*** @author wangbin* @description 进行加锁的操作(该方法是单线程运行的)* @date 2019年09月20日* @param key 某个方法请求url加上cookie中的用户身份使用md5加密生成* @param value 当前时间+过期时间(10秒)* @return true表示加锁成功false表示未获取到锁*/public boolean lock(String key,String value){//加锁成功返回trueif(redisTemplate.opsForValue().setIfAbsent(key,value,10, TimeUnit.SECONDS)){return true; }String currentValue = https://www.songbingjia.com/android/redisTemplate.opsForValue().get(key); //加锁失败,再判断是否由于解锁失败造成了死锁的情况if(StringUtils.isNotEmpty(currentValue) & & Long.parseLong(currentValue) < System.currentTimeMillis()){//获取上一个锁的时间,并且重新设置锁String oldValue = redisTemplate.opsForValue().getAndSet(key, value); if(StringUtils.isNotEmpty(oldValue) & & oldValue.equals(currentValue)){//设置成功,重新设置锁是保证了单线程的运行return true; }}return false; }/*** @author wangbin* @description 进行解锁的操作* @date 2019年09月20日* @param key 某个方法请求url使用md5加密生成* @param value 当前时间+过期时间* @return*/public void unLock(String key,String value){try {String currentValue = redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue) & & currentValue.equals(value)){redisTemplate.delete(key); }}catch (Exception e){logger.error("redis分布式锁,解锁异常",e); }}/*** @author wangbin* @description 进行解锁的操作* @date 2019年09月20日* @param key 某个方法请求url使用md5加密生成* @return*/public void unLock(String key){try {String currentValue = https://www.songbingjia.com/android/redisTemplate.opsForValue().get(key); if(StringUtils.isNotEmpty(currentValue)){redisTemplate.delete(key); }}catch (Exception e){logger.error("redis分布式锁,解锁异常",e); }} }
3.使用拦截器在请求之前进行加锁的判断。
@Configuration public class LoginInterceptor extends HandlerInterceptorAdapter {private final Logger logger = LoggerFactory.getLogger(LoginInterceptor.class); //超时时间设置为10秒private static final int timeOut = 10000; @Autowiredprivate StringRedisTemplate stringRedisTemplate; @Autowiredprivate RedisLock redisLock; /*** 在请求处理之前进行调用(Controller方法调用之前)* 基于URL实现的拦截器* @param request* @param response* @param handler* @return* @throws Exception*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {String path = request.getServletPath(); if (path.matches(Constants.NO_INTERCEPTOR_PATH)) {//不需要的拦截直接过return true; } else {// 这写你拦截需要干的事儿,比如取缓存,SESSION,权限判断等//判断是否是重复提交的请求if(!redisLock.lock(DigestUtils.md5Hex(request.getRequestURI()+value),String.valueOf(System.currentTimeMillis()+timeOut))){logger.info("===========获取锁失败,该请求为重复提交请求"); return false; }return true; }} }
4.使用aop在后置通知中进行解锁。
/*** @author wangbin* @description 使用redis分布式锁解决表单重复提交的问题* @date 2019年09月20日*/ @Aspect @Component public class RepeatedSubmit {@Autowiredprivate RedisLock redisLock; //定义切点@Pointcut("execution(public * com.kunluntop.logistics.controller..*.*(..))")public void pointcut(){}//在方法执行完成后释放锁@After("pointcut()")public void after(){ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request = attributes.getRequest(); redisLock.unLock(DigestUtils.md5Hex(request.getRequestURI()+ CookieUtils.getCookie(request,"userkey"))); } }
到此这篇关于redis分布式锁解决表单重复提交的问题的文章就介绍到这了
【简单介绍redis分布式锁解决表单重复提交的问题】本文地址:??https://www.linuxprobe.com/redis-linux-like.html??
推荐阅读
- disk_lvm.sh
- 十docker swarm
- linux学习--基础shell练习
- 在pfSense中配置ZeroTier网络
- 十一docker config和docker secret
- Ansible配置执行远程主机的ssh端口号
- xp系统下的2345浏览页面时经常页面不显示应该如何处理?
- xp系统不能打开帮助与支持应该处理这个问题?
- XP系统应该如何设置按照摄影机型号进行排列照片文件?