sessionid会重复吗_springboot2.2.X手册:分布式系统下,重复提交的解决方案

上一篇:springboot2.2.X手册:是时候用Lettuce替换Jedis操作Redis缓存了

上一篇中我们讲解了redis,主要是因为接下来的更新,都会涉及到redis的操作,所以就放在上一篇了。

今天我们主要讲解重复提交的问题,这种问题,算是比较常见,但是又容易出问题,加上现在基本上都是微服务架构,今天来聊一下在分布式系统下,如果防止重复提交。

0ddbb5aec4efa6a0c34e28ab99eb7281.png

什么是幂等性

小编以前面试过一家公司,被问到什么是幂等性,当时不懂,就瞎扯了一番,惨遭面试官鄙视。

幂等性指的是多次运算结果一样,用公式来表示就是F(F(x))=F(x)。

在我们的对数据库的操作中,以下操作就是幂等性

select查询就是最基础的幂等性

delete删除也是一样,删除多少次都是一样的结果

update这里分两种,如果是更新某个值,那就是幂等性;如果是更新累加操作的,那就是非幂等性。

insert是非幂等性操作,毕竟每次都增加一条,从而导致数据变化了

4f143e72ba511557e9665d7322fbcd65.png

重复提交如何产生

重复问题发生的情况比较多,小编总结了一下以下几点

1、提交按钮点击两次

2、浏览器提交后进行后退操作,然后再一次提交

3、使用浏览器的历史记录进行重复提交表单

4、重复的请求浏览器的http请求

5、nginx不断重新发送

6、分布式RPC中,进行了try重试等

876d0fecd5ba4acf1ad07c579eeba9ed.png

基于redis的防止重复提交

今天我们来讲解一种方法,基于redis的重复提交的防止方案,只供参考。

引入POM文件

org.springframework.bootspring-boot-starter-webcom.bootsmodule-boots-redis1.0.0.RELEASEorg.springframework.bootspring-boot-starter-aop

新建重复提交注解

/** * 重复提交注解 * @author:溪云阁 * @date:2020年5月24日 */public @interface NoRepeatSubmit {}

新建重复提交拦截

/** * 重复提交拦截 * @author:溪云阁 * @date:2020年5月24日 */@Aspect@Component@Slf4jpublic class RepeatSubmit {    @Autowired    private RedisUtils redisUtils;    /**     * 重复提交拦截     * @author 溪云阁     * @param pjp     * @return Object     */    @Around(value = "@annotation(com.module.boots.submit.NoRepeatSubmit)")    public Object arround(ProceedingJoinPoint pjp) {        Object obj = null;        try {            final ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();            final String sessionId = RequestContextHolder.getRequestAttributes().getSessionId();            final HttpServletRequest request = attributes.getRequest();            final HttpServletResponse response = attributes.getResponse();            final String key = sessionId + "-" + request.getServletPath();            // 如果缓存中有这个url视为重复提交            if (redisUtils.get(key) == null) {                obj = pjp.proceed();                redisUtils.set(key, 0, 2);            } else {                log.error("重复提交");                response.setStatus(HttpServletResponse.SC_METHOD_NOT_ALLOWED);                response.setContentType("application/json;charset=UTF-8");                response.getOutputStream().write(buildFailureMsg("重复提交,请稍后再提交").toString().getBytes("utf-8"));            }        }        catch (final Throwable e) {            e.printStackTrace();            log.error("验证重复提交时出现未知异常!");            return buildFailureMsg("重复提交出现问题").toJSONString();        }        return obj;    }    /**     * 自定义错误信息     * @author 溪云阁     * @param errMsg     * @return JSONObject     */    private JSONObject buildFailureMsg(String errMsg) {        final JSONObject json = new JSONObject();        json.put("respStatus", "01");        json.put("respDesc", errMsg);        json.put("data", null);        return json;    }}

新增redis配置

# redis地址spring.redis.host: 127.0.0.1# redis端口号spring.redis.port: 6379# redis密码,如果没有不用填写,建议还是得有spring.redis.password: 123456# 最大活跃连接数,默认是8spring.redis.lettuce.pool.maxActive: 100# 最大空闲连接数 ,默认是8spring.redis.lettuce.pool.maxIdle: 100# 最小空闲连接数 ,默认是0spring.redis.lettuce.pool.minIdle: 0

新建测试类

/** * @author:溪云阁 * @date:2020年5月24日 */@SuppressWarnings("deprecation")@Api(tags = { "WEB服务:数据接口" })@RestController@RequestMapping("web/submit")public class SubmitController {    /**     * 获取字符串信息     * @author 溪云阁     * @param id     * @param name     * @return ResponseMsg     */    @ApiOperation(value = "获取字符串信息")    @GetMapping(value = "/getString", produces = MediaType.APPLICATION_JSON_UTF8_VALUE)    @NoRepeatSubmit    @SneakyThrows(CommonRuntimeException.class)    public ResponseMsg getString(@RequestParam("id") String id, @RequestParam("name") String name) {        final JSONObject json = new JSONObject();        json.put("id", id);        json.put("name", name);        return MsgUtils.buildSuccessMsg(json);    }}
6cad2ea0aca364e0cb11b0bb9907d323.png

在进行接口调试中,我们点击多次提交,快速一些,可以看到提示,证明成功。

当你的服务进行拓展的时候,进行提交后,只会去redis进行验证,从而可以实现集群化部署而不用担心单个服务重复提交问题。

--END--

作者:@溪云阁

如需要源码,转发,关注后私信我。

部分图片或代码来源网络,如侵权请联系删除,谢谢!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值