一,什么是幂等性?

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. [LeetCode] 17. 电话号码的字母组合(回溯)

    题目 给定一个仅包含数字 2-9 的字符串,返回所有它能表示的字母组合. 给出数字到字母的映射如下(与电话按键相同).注意 1 不对应任何字母. 示例: 输入:"23" 输出:[& ...

  2. 使用App Metrics实现性能监控

    App Metrics监控需要安装InfluxDB时序数据库和Grafana可视化分析工具 1.安装InfluxDB 下载地址:https://portal.influxdata.com/downlo ...

  3. 阿里云docker部署mysql

    看完我的上一个博客之后,对centos系统应该有一定的了解,话不多说,接下来我们来在docker容器中部署mysql. 1.下载mysql镜像,因为本人用的5.7版本,你也可以下载最新版,都是可以的 ...

  4. Centos 7 redis、tomcat、Spring Boot添加开机自启服务

    一.redis添加开机自启 1.添加服务配置文件 [root@test system]# vim /etc/systemd/system/redis-server.service 2.服务配置文件内容 ...

  5. HTML+CSS使用swiper快速生成最简单、最快捷、最易看懂的轮播图

    1.  在网页顶部输入swiper.com.con,进入swiper官网 2.   点击" API文档",获取轮播图代码的地方 3.   点击左侧"swiper初始化&q ...

  6. mysqldump 5.7

    简介 mysqldump是官方自带的文本格式备份工具,简单实用,一般在Mysql安装目录的bin目录下.备份文件默认是SQL格式,它由一系列语句例如CREATE TABLE.INSERT等组成.mys ...

  7. pycharm 配置 github

    今天突然想把自己的代码上传到github上去,然后就研究了下pycharm的配置. 首先呢,你得有个github的账号,然后建立一个项目. 然后打开pycharm,选择file->Setting ...

  8. 硬核测试:Pulsar 与 Kafka 在金融场景下的性能分析

    背景 Apache Pulsar 是下一代分布式消息流平台,采用计算存储分层架构,具备多租户.高一致.高性能.百万 topic.数据平滑迁移等诸多优势.越来越多的企业正在使用 Pulsar 或者尝试将 ...

  9. 在Centos6上安装RabbitMQ的过程(有点坑)

    1.安装依赖环境 yum install build-essential openssl openssl-devel unixODBC unixODBC-devel make gcc gcc-c++ ...

  10. 安卓app功能或自动化测试覆盖率统计(不用instrumentation启动app)

    一文带你揭秘如何采取非instrumentation启动app,打造实时统计覆盖率,一键触发覆盖率测试报告. 在上篇文章,一文带你解决Android app手工测试或者自动化测试覆盖率统计(撸代码版) ...