前言:本章主要解决我们在操作表单(更新)数据造成多次点击提交,数据库添加多条数据问题!!
解决方式:使用幂等的方式保证一次和多次的请求结果一致
幂等性介绍
幂等性的概念 : 任意多次执行所产生的影响都与一次执行产生的影响相同
意思就是说对数据库的影响只能是一次性的,不能重复处理
为什么使用幂等性?
在系统高并发的环境下,很有可能因为网络,阻塞等等问题导致客户端或者调用方并不能及时的收到服务端的反馈甚至是调用超时的问题,即请求方调用了你的服务,但是没有收到任何的信息,完全懵的状态。
比如订单的问题,可能会遇到如下的几个问题:
创建订单时,第一次调用服务超时,再次调用是否产生两笔订单?
订单创建成功去减库存时,第一次减库存超时,是否会多扣一次?
订单支付时,服务端扣钱成功,但是接口反馈超时,此时再次调用支付,是否会多扣一笔呢?
以上三种情况,都不太合适,因此需要使用幂等性保障对数据库的影响只能是一次性的,不能重复处理
主要分享以token机制解决重复提交数据问题
Redis实现自动幂等性原理(下图)
1 .(controller层代码) 创建生成token,并携带token跳转页面
@GetMapping("addSimple")//跳转到注册页面
public String add(Model model) {
UUID token = UUID.randomUUID();//创建唯一id
model.addAttribute("token", token);//产生token
return "addSimple";
}
2.(页面代码html/jsp) ajax提交携带存入的token传入后端
<form action="add" method="post">
<input type="hidden" name="token" value="${token}">
<button type="button" onclick="add()">提交</button>
</form>
</body>
<script>
function add() {
$.post("add", $("form").serialize(), function (obj) {
if (obj) {
alert("正常提交");
} else {
alert("重复提交")
}
})
}
</script>
3.(controller层代码) 第一次提价将token存入redis(key-value),进行判断,即可解决重复提交问题
@ResponseBody
@PostMapping("addSimple")
public boolean add(User user, String token) {
//如果redis没有该key ,则存入redis并且设置超时时间2秒,2秒内提交均为重复操作
Boolean b = redisTemplate.opsForValue().setIfAbsent(token, token, 2, TimeUnit.SECONDS);
if (b) {//第一次提交
userService.add(user);
return true;
}
//token已存在,重复提交,不执行数据
return false;
}
.setIfAbsent用法普及
redisTemplate.opsForValue().setIfAbsent(key,value,timeout,timeUnit) /* key:键名 value:值 timeout:存活时间 timeUnit:时间格式,TimeUnit.SECONDS(秒) timeunit使用 TimeUnit.DAYS //天 TimeUnit.HOURS //小时 TimeUnit.MINUTES //分钟 TimeUnit.SECONDS //秒 TimeUnit.MILLISECONDS //毫秒 */
该方法的用法是: 判断redis中指定key是否存在,不存在创建并指定key生存时间返回true
已存在,无效操作,返回false
推荐 : Spring&redis整合RedisTemplate操作{String、List、Set、Zset、Hash}五种数据类型常用方法【超详细+附过程效果图】_萌小崔的博客-CSDN博客
至此(幂等性)token机制解决重复提交问题已解决了,有疑问留言互动,谢谢查看!!
Thanks!