java 防重_关于java:如何做一个防重设计

本文探讨了业务设计中防重的重要性,分析了导致接口重复调用的各种原因,包括攻击、用户误操作和超时重试。接着介绍了如何通过Token机制、防重Key、防重表等方法实现防重,并详细讲解了插入和更新操作的防重策略,如乐观锁和状态机。最后,强调了防重方法的选择应根据业务需求和系统特性来确定。
摘要由CSDN通过智能技术生成

前言

在业务设计中防重设计是一个关键点,以接口设计为例,防重就是避免接口被屡次调用而产生脏数据,比方领取订单呈现反复领取,所以说防重至关重要,在如何防重之前咱们首先看一下是如何呈现反复申请的。

何时呈现屡次调用

屡次调用接口的呈现有主观原因比方:人为的反复申请攻打,用户的误操作等;也有客观原因比方:为了健壮性进行超时重试;

反复申请攻打

对于这种歹意攻打,其实曾经属于平安领域了,咱们能够通过黑名单+限流来解决,下一步再思考防重解决;

用户的误操作

比方用户在界面点击提交按钮,因为手误呈现屡次点击提交,这种状况客户端能够做一些解决,缩小用户的误操作,比方提交完按钮变灰等;当然提供方的防重解决也是必不可少的;

超时重试

接口调用方为了保证系统的健壮性,往往会做一些重试解决,比方各种RPC框架都曾经帮咱们内置了容错机制,提供方须要做好防重;

如何做好防重解决,其实外围就是保障多个雷同的申请只有一次被执行,或者说屡次调用和一次调用产生的成果是一样的,也就是咱们常常说的要保障幂等性;

何时须要防重

所有的操作说到底都是增删改查,其实咱们真正须要做防重解决的,更重要的是减少和批改;查问和删除自身执行一次和屡次,产生的成果是一样的,有人造幂等性,尽管说有人造幂等性,然而查问和删除自身也是要耗费资源的,如果能避免反复执行,也能节俭资源;

减少和批改是必须要做防重的,减少能够以下单为例,批改能够以更新库存为例,如果没有做好防重结果是十分重大的;上面具体看看都有哪些防重的措施;

如何防重

下面说到次要是针对减少和批改须要做好防重解决,当然针对减少和批改其实是有不同的防重措施,也有对立的形式,上面别离介绍;

对立防重

token机制

服务器须要提供获取token机制的服务,这样每次客户端申请的时候先获取token,服务器端会将token保留在redis中;客户端发送申请的时候会带上token,这样服务器端能够拿到token间接去redis中做删除解决,依据返回值判断是否胜利:

localhost:0>get token

"111"

localhost:0>del token

"1"

localhost:0>del token

"0"

通过redis寄存token,这样在分布式环境下也能很好的工作;

防重key

依据申请参数生成md5密文,而后用此密文作为key存入redis中,能够通过应用setnx命令来保障只有一个能保留胜利;

key = MD5.md5("param1="+param1+"&param2="+param2...)

localhost:0>setnx key 1

"1"

localhost:0>setnx key 1

"0"

防重表

能够利用表的惟一索引束缚,能够应用相似防重key作为惟一索引字段,屡次申请过去只会有一个插入胜利,为了避免防重表数据过多,能够启动一个定时器定时清理;

以上几种形式其实和具体的业务关系不大,能够实用大部分场景;而且通过redis或者数据库,以及原子性操作来保障在分布式环境下也能够很好的运行;

插入防重

select+insert

插入数据最先想到就是先查看有没有,而后在插入,然而这样显著存在两个操作,不是原子性操作,单节点下还能通过锁来解决,分布式环境下就须要用到分布式锁来保障原子性了;当然也能够联合其余形式一起应用,比方上面的惟一主键机制;

惟一主键

这种形式其实就是不间接应用数据库的自增主键了,应用分布式id算法生成,这样在插入数据的时候就能够通过惟一主键来进行束缚,保障只会有一条胜利;

回滚机制

有些业务其实是有正向流程和逆向流程,比方领取订单,在接管到银行返回的领取胜利告诉时判断订单的状态,如果曾经领取胜利,能够间接走退款流程;

更新防重

乐观锁形式

乐观锁常被用在更新场景中,如上面通过版本号的形式来实现:

update table_name

sale = sale + 1,

version = version + 1,

WHERE id = #{id}

AND version = #{version}

状态机乐观锁

在相干订单的业务中,很多都会波及到状态机,状态是流转的,有了上一个状态才会有下一个状态,比方常见的购物订单包含:提交未领取,领取胜利,待发货,发货中,已签收等,每个状态都须要前置状态;

update table_name

set  status = 下一个状态

where  id = #{id}

and status = #{status}

总结

防重的办法很多,咱们往往须要更加本人的业务做相干的抉择,不同的业务,不同的业务量,不同的容忍水平都会影响咱们如何去做防重;每种形式也不是都是独立存在的,有时候往往须要多种形式整合起来。

感激关注

能够关注微信公众号「 回滚吧代码」,第一工夫浏览,文章继续更新;专一Java源码、架构、算法和面试。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值