一,什么是幂等性?

1,幂等:

幂等操作:不管执行多少次,所产生的影响都和一次执行的影响相同。

幂等函数或幂等方法:可以使用相同的参数重复执行,并能获得相同的结果的函数/方法。

这些函数/方法不用担心重复执行会对系统造成改变。

2,幂等操作的一些例子:

前端重复提交相同的数据,后台只产生对应这个数据的一个相同的反应结果

发送验证码短信:应该只发一次,相同的验证短信不能多次发送。

生成订单:一个业务请求只能创建一个订单,不能重复创建相同的订单

用户付款:只能扣用户一次钱,不能重复扣费

3,实现幂等操作的一些方法:

unique索引

悲观锁

乐观锁

token机制

...

说明:刘宏缔的架构森林是一个专注架构的博客,地址:https://www.cnblogs.com/architectforest

对应的源码可以访问这里获取: https://github.com/liuhongdi/

说明:作者:刘宏缔 邮箱: 371125307@qq.com

二,关于演示代码的说明:

1,项目的原理:

我们这里的演示的是表单提交时要避免重复提交相同的内容,

前端在用户点击提交按钮后,需要在后端返回结果之前,禁止用户再次点击提交按钮,

假如有请求绕过了前端的控制,直接向后端发送重复的相同请求,

后端如何避免?

在用户打开表单时,后端会生成一个token字符串,保存在redis后,传递给表单,

当表单提交时,这个字符串会再次提交到后端接口,

后端接口需要判断这个字符串是否在redis中存在?

如果不存在不允许提交,如果存在删除时能成功删除,允许提交,

删除时报错:表示已被其他进程删除,也不能允许提交.

2,项目在github的地址:

https://github.com/liuhongdi/idempotent

3,代码结构截图:

三,lua代码的说明:

checkidem.lua

local current = redis.call('GET', KEYS[1])
if current == false then
--redis.log(redis.LOG_NOTICE,KEYS[1]..' is nil ')
return '-1'
end
local isdel = redis.call('DEL', KEYS[1])
if isdel == 1 then
--redis.log(redis.LOG_NOTICE,' del '..KEYS[1]..' success')
return '1';
else
--redis.log(redis.LOG_NOTICE,'del '..KEYS[1]..' failed')
return '0';
end

如果当前token在redis中不存在,返回 -1

如果token存在,删除成功,返回1

删除失败,返回0

说明:为什么使用lua脚本?

redis上的lua脚本的执行是原子性的,不存在多个线程的并发问题,

使用lua脚本能保证不会出现重复的提交

四,java代码的说明:

1,RedisLuaUtil

@Service
public class RedisLuaUtil {
@Resource
private StringRedisTemplate stringRedisTemplate; /*
run a lua script
luaFileName: lua file name,no path
keyList: list for redis key
return 0: delete fail
-1: no this key
1: delete success
*/
public String runLuaScript(String luaFileName,List<String> keyList) {
//System.out.println("redis script begin");
DefaultRedisScript<String> redisScript = new DefaultRedisScript<>();
redisScript.setScriptSource(new ResourceScriptSource(new ClassPathResource("lua/"+luaFileName)));
redisScript.setResultType(String.class); String argsone = "none";
//System.out.println("execute begin");
String result = stringRedisTemplate.execute(redisScript, keyList,argsone);
System.out.println("lua result:"+result); return result;
}
}

说明:

DefaultRedisScript:负责封装lua脚本

luaFileName: lua文件名

keyList:   redis中的key列表,我们只需要传递token即可

stringRedisTemplate:负责执行脚本

argsone:值参数,我们传一个空字串即可

2,TokenServiceImpl.java中对redisLuaUtil类的调用

    @Override
public void checkToken(HttpServletRequest request) { String token = request.getHeader(TOKEN_NAME); if (StringUtils.isBlank(token)) {// header中不存在token
token = request.getParameter(TOKEN_NAME);
if (StringUtils.isBlank(token)) {// parameter中也不存在token
//System.out.println("-----no token");
throw new ServiceException(ResponseCode.ILLEGAL_ARGUMENT.getMsg());
}
} //System.out.println("runlua begin");
List<String> keyList = new ArrayList();
keyList.add(token);
String res = redisLuaUtil.runLuaScript("checkidem.lua",keyList); if (res.equals("1")) {
ServerResponseUtil.success("success");
} else {
throw new ServiceException(ResponseCode.REPETITIVE_OPERATION.getMsg());
}
}

五,测试幂等性的检测是否生效?

提交表单前,先得到token

访问:

http://127.0.0.1:8080/order/gettoken

返回:

{"status":0,"msg":"8IgWPMtotKyzO13pnxCS9pc4","data":null}

用ab测试表单:

#-c:指定请求的并发数量

#-n:指定请求的总数量

[root@localhost etc]# ab -c 10 -n 10 http://127.0.0.1:8080/order/addorder?form_token=8IgWPMtotKyzO13pnxCS9pc4

查看代码中system.out.println的打印输出:

lua result:1
lua result:-1
lua result:-1
lua result:-1
lua result:-1
lua result:-1
lua result:-1
lua result:-1
lua result:-1
lua result:-1

可以看到只有一个是提交成功,其他的请求均给出了报错

六,查看spring boot的版本:

  .   ____          _            __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v2.2.0.RELEASE)

spring boot:用redis+lua实现表单接口的幂等性(spring boot 2.2.0)的更多相关文章

  1. Spring Security默认的用户登录表单 页面源代码

    Spring Security默认的用户登录表单 页面源代码 <html><head><title>Login Page</title></hea ...

  2. spring boot:用redis+lua限制短信验证码的发送频率(spring boot 2.3.2)

    一,为什么要限制短信验证码的发送频率? 1,短信验证码每条短信都有成本制约, 肯定不能被刷接口的乱发 而且接口被刷会影响到用户的体验, 影响服务端的正常访问, 所以既使有图形验证码等的保护, 我们仍然 ...

  3. Spring Boot 2 + Thymeleaf:服务器端表单验证

    表单验证分为前端验证和服务器端验证.服务器端验证方面,Java提供了主要用于数据验证的JSR 303规范,而Hibernate Validator实现了JSR 303规范.项目依赖加入spring-b ...

  4. spring boot学习(7) SpringBoot 之表单验证

    第一节:SpringBoot 之表单验证@Valid 是spring-data-jpa的功能:   下面是添加学生的信息例子,要求姓名不能为空,年龄大于18岁.   贴下代码吧: Student实体: ...

  5. 【Spring学习笔记-MVC-11--】Spring MVC之表单标签

    一.使用方法 1.要使用Spring MVC提供的表单标签,首先需要在视图页面添加: <%@ taglib prefix="form" uri="http://ww ...

  6. spring-security-4 (5)spring security Java配置实现自定义表单认证与授权

    前面三篇讲解了spring security的搭建以及简单的表单认证与授权原理.本篇将实现我们自定义的表单登录与认证.  本篇不会再讲项目的搭建过程,因为跟第二节的搭建如出一辙.本篇也不会将项目中所有 ...

  7. SpringBoot集成Spring Security(4)——自定义表单登录

    通过前面三篇文章,你应该大致了解了 Spring Security 的流程.你应该发现了,真正的 login 请求是由 Spring Security 帮我们处理的,那么我们如何实现自定义表单登录呢, ...

  8. Spring MVC(十四)--SpringMVC验证表单

    在Spring MVC中提供了验证器可以进行服务端校验,所有的验证都必须先注册校验器,不过校验器也是Spring MVC自动加载的,在使用Spring MVC校验器之前首先要下载相关的jar包,下面是 ...

  9. spring mvc Controller与jquery Form表单提交代码demo

    1.JSP表单 <% String basePath = request.getScheme() + "://" + request.getServerName() +&qu ...

随机推荐

  1. 【小程序】---- 使用 Echarts 的方式

    1.下载 GitHub 上的 ecomfe/echarts-for-weixin 项目,Echarts微信版. 地址:https://github.com/ecomfe/echarts-for-wei ...

  2. sql注入--bool盲注,时间盲注

    盲注定义: 有时目标存在注入,但在页面上没有任何回显,此时,我们需要利用一些方法进行判断或者尝试得到数据,这个过程称之为盲注. 布尔盲注: 布尔盲注只有true跟false,也就是说它根据你的注入信息 ...

  3. Tomcat http转https

    1.先申请ssl   腾讯  阿里都有免费的一年的 2.修改tomcat  conf文件夹的service.xml文件 <!-- 将所有的8443  改为443 --> <Conne ...

  4. java 多线程-4

    十四.sleep方法和wait方法的区别 [面试题] 相同点: 一旦执行方法,都可以使得当前线程进入阻塞状态. 不同点: 两个方法的声明位置不同:Thread类声明sleep():Object类中声明 ...

  5. FTP服务端 FTP服务端搭建教程

    FTP服务端搭建教程如下:一.需要准备以下工具:1.微型FTP服务端.2.服务器管理工具二.操作步骤:1.下载微型FTP服务端.(站长工具包可下载:http://zzgjb.iis7.com/ )2. ...

  6. if-else​ 条件语句

    1.  条件语句模型 Go里的流程控制方法还是挺丰富,整理了下有如下这么多种: if - else 条件语句 switch - case 选择语句 for - range 循环语句 goto 无条件跳 ...

  7. JVM学习目录

    JVM学习目录 JVM的整体结构 1.类加载子系统 类加载子系统 2.运行时数据区 运行时数据区总览 堆.栈.方法区的详细图解 2.1.程序计数器 程序计数器 2.2.本地方法栈 本地方法栈 2.3. ...

  8. Spring事务管理(编码式、配置文件方式、注解方式)

    1.事务(https://www.cnblogs.com/zhai1997/p/11710082.html) (1)事务的特性:acdi (2)事务的并发问题:丢失修改,脏读,不可重复读 (3)事务的 ...

  9. UnityShader学习笔记- Stencil Buffer

    模板测试(Stencil Test)是现代渲染流水线的一环,其中涉及到的就是模板缓冲(Stencil Buffer),模板缓冲可以用来制作物体的遮罩.轮廓描边.阴影.遮挡显示等等效果 目录 Stenc ...

  10. Azure 内容审查器之文本审查

    内容审查器 Azure 内容审查器也是一项认知服务.它支持对文本.图形.视频进行内容审核.可以过滤出某些不健康的内容,关键词.使你的网站内容符合当地的法律法规,提供更好的用户体验. 文本内容审核 其中 ...