网站后台管理系统栏目位置,北京装饰公司名称大全,互联网保险和线下保险的优缺点,购物网站开发 项目描述优质博文#xff1a;IT-BLOG-CN 
幂等 操作的特点是一次和多次请求某一个资源对于资源本身应该具有同样的结果#xff08;网络超时等问题除外#xff09;。幂等函数或幂等方法是指可以使用相同参数重复执行#xff0c;并能获得相同结果的函数。这些函数不会影响系统状态IT-BLOG-CN 
幂等 操作的特点是一次和多次请求某一个资源对于资源本身应该具有同样的结果网络超时等问题除外。幂等函数或幂等方法是指可以使用相同参数重复执行并能获得相同结果的函数。这些函数不会影响系统状态也不用担心重复执行会对系统造成改变。这对于保证系统的一致性和可靠性非常重要。 
具体来说当一个接口被设计为幂等的时候无论请求被执行多少次结果都是一样的。这样可以避免由于网络延迟、重试或其他原因导致的重复请求对系统造成的副作用比如重复创建订单、重复扣款等。实现接口幂等性可以提高系统的可靠性和稳定性减少不必要的资源消耗和数据错误。同时对于一些需要保证数据一致性的操作比如金融交易、库存管理等实现接口幂等性也是非常重要的。 
一、为什么要实现接口幂等性 
【1】前端重复提交表单 在填写一些表格时候用户填写完成提交很多时候会因网络波动没有及时对用户做出提交成功响应致使用户认为没有成功提交然后一直点提交按钮这时就会发生重复提交表单请求。 【2】接口超时重复提交 很多时候HTTP客户端工具都默认开启超时重试的机制尤其是第三方调用接口时候为了防止网络波动超时等造成的请求失败都会添加重试机制导致一个请求提交多次。 【3】消息进行重复消费 当使用MQ消息中间件时候如果发生消息中间件出现错误未及时提交消费信息导致发生重复消费。 【4】用户恶意进行刷单 在实现用户投票这种功能时如果用户针对一个用户进行重复提交投票这样会导致接口接收到用户重复提交的投票信息这样会使投票结果与事实严重不符。 
二、什么时候做幂等性 
请求类型是否需要幂等描述Get自身满足幂等性Get 方法用于获取资源。其一般不会也不应当对系统资源进行改变所以是幂等的。Post自身不满足幂等性Post 方法一般用于创建新的资源。其每次执行都会新增数据所以不是幂等的。Put可能满足可能不满足Put 方法一般用于修改资源。该操作则分情况来判断是不是满足幂等更新操作中直接根据某个值进行更新也能保持幂等。不过执行累加操作的更新是非幂等。Delete可能满足可能不满足Delete 方法一般用于删除资源。该操作则分情况来判断是不是满足幂等当根据唯一值进行删除时删除同一个数据多次执行效果一样。但带查询条件的删除就不一定满足幂等例如在根据某条件删除一批数据后这时候新增加了一条数据也满足条件然后又执行了一次删除那么将会导致新增加的这条满足条件数据也被删除。 
三、如何实现幂等性 
客户端 客户端防止重复提交并不是绝对可靠的可以通过工具略过前端直接访问后端。优点是实现起来比较简单。 按钮只能操作一次 
提交后把按钮置灰或loding状态消除用户因为重复点击而产生的重复记录比如添加操作由于点击两次而产生两条记录。 
使用Post/Redirect/Get模式 
在提交后执行页面重定向这就是所谓的Post-Redirect—Get(PRG)模式。当用户提交表单后跳转到一个重定向的信息页面避免用户按F5刷新导致的重复提交而且也不会出现浏览器表单重复提交的警告也能消除按浏览器前进和后退导致同样重复提交的问题。 
服务端 
数据库唯一主键 
利用数据库中主键唯一约束的特性一般来说唯一主键比较适用于“插入”时的幂等性其能保证一张表中只能存在一条带该唯一主键的记录。使用数据库唯一主键完成幂等性时需要注意的是该主键一般来说并不是使用数据库中自增主键而是使用分布式ID充当主键这样才能能保证在分布式环境下ID的全局唯一性。 唯一索引 
与唯一主键的思想一致通过唯一性确保插入的幂等性。创建订单时前端先通过接口获取订单号再请求后端时带入订单号订单表中订单号添加唯一索引如果存在插入相同订单号则直接报错。消费MQ消息时messageId是唯一的我们可以新添加一种消费记录表将messageId作为主键如果重复消费那么就会存在相同的messageId插入直接报错。 
乐观锁 
乐观锁就是很乐观每次去拿数据的时候都认为别人不会修改所以不会上锁但是在更新的时候会判断一下在此期间别人有没有去更新这个数据可以使用版本号机制。数据库乐观锁一般只能适用于执行“更新操作”的过程我们可以提前在对应的数据表中多添加一个字段充当当前数据的版本标识。每次对该数据库数据执行更新时都会将该版本标识作为一个条件值为上次待更新数据的版本标识。 悲观锁 
当对数据库中的一条数据进行修改的时候为了避免同时被其他人修改最好的办法就是直接对该数据进行加锁以防止并发。如下伪代码通过for update添加悲观锁这里order_id需要有索引否则会锁整张表。悲观锁影响性能一般不建议。 
begin;  --  1.开始事务--  查询订单判断状态select order_id,status from orders where order_id1000234 for update ifstatus ! S{-- 非订单状态不能更新为已完成return ;}--  更新完成update order set statuss order_no1000234 
commit; -- 2.提交事务状态码 
很多业务表都是有状态的比如订单表,一般订单有1-订单创建、2-订单支付、3-订单完成、4-取消订单等订单流程当我们更新订单状态 
update orders set status3 where order_id1000234 and status2;第一次请求时将“订单支付”状态修改成“订单完成”sql执行结果的影响行数是1。 第二次重复请求时同样将“订单支付”状态修改成“订单完成”但是sql执行结果的影响行数为0。如果是0那么我们直接可以返回成功了。不需要做接下来的业务操作以此来保证保证接口的幂等性。 
基于分布式锁 
分布式锁实现幂等性的逻辑就是请求过来时先去尝试获得分布式锁如果获得成功就执行业务逻辑反之获取失败的话就舍弃请求直接返回成功。其实前面介绍过的悲观锁本质是使用了数据库的分布式锁都是将多个操作打包成一个原子操作保证幂等。但由于数据库分布式锁的性能不太好我们都是通过Redis或Zookeeper来实现分布式锁。 
客户端  服务端 
Token机制 
针对客户端连续点击或者调用方的超时重试等情况可以用Token的机制实现防止重复提交。简单的说就是调用方在调用接口的时候先向后端请求一个全局IDToken请求的时候携带这个全局ID一起请求Token最好将其放到Headers中后端需要对这个Token作为Key用户信息作为Value到Redis中进行键值内容校验如果Key存在且Value匹配就执行删除命令然后正常执行后面的业务逻辑。如果不存在对应的Key或Value不匹配就返回重复执行的错误信息这样来保证幂等操作。 Token工具类 接收Token串加上Key前缀形成Key再传入value值执行Lua表达式保证命令执行的原子性查找对应Key与删除操作。执行完成后验证命令的返回结果如果结果不为空且非0则验证成功否则失败。 
public class TockenUtlls {Autowiredprivate RedisTemplate redisTemplate;// token前缀private static final String TOKEN_PRE  token_;// 创建 token 并传入 Redispublic String generateToken(String value) { // 通过 UUID 创建 TokenString token  UUID.randomUUID().toString();String key  TOKEN_PRE  token;// 存储 Token 到 Redis 并设置超时时间redisTemplate.opsForValue().set(key, value, 10, TimeUnit.MINUTES);return token;}// 验证 Tokenpublic boolean validToken(String token, String value) {// 设置 LUA 脚本 KEYS[1] 代表 key KEYS[2] 代表 valueString luaScript   if redis.call(get, KEYS[1])  KEYS[2]then return redis.call(get, KEYS[1]) else return 0 end ;RedisScriptLong redisScript  new DefaultRedisScript(script, Long.class);// 拼接 Redis KeyString key  TOKEN_PRE  token;// 执行 LUA 脚本Long result  redisTemplate.execute(redisScript, Arrays.asList(key, value));// 根据返回值判断是否匹配成功并删除 Redis 键值对。   结果不为空则表示成功if (result ! null  result ! 0L) {redisTemplate.opsForValue().getAndDelete(key);return true;}return false;}
}唯一序号 
所谓请求序列号其实就是每次向服务端请求时候附带一个短时间内唯一不重复的序列号该序列号可以是一个有序ID也可以是一个订单号一般由上游生成在调用下游服务端接口时附加该序列号和用于认证的ID。当下游服务器收到请求信息后拿取该“序列号”和上游认证ID进行组合形成用于操作Redis的Key然后到Redis中查询是否存在对应的Key的键值对如果不存在就以该Key作为Redis的键以上游关键信息作为存储的值将该键值对存储到Redis中 然后再正常执行对应的业务逻辑即可。 
 文章转载自: http://www.morning.wcqxj.cn.gov.cn.wcqxj.cn http://www.morning.lxyyp.cn.gov.cn.lxyyp.cn http://www.morning.kzhgy.cn.gov.cn.kzhgy.cn http://www.morning.kqrql.cn.gov.cn.kqrql.cn http://www.morning.yzdth.cn.gov.cn.yzdth.cn http://www.morning.zlrsy.cn.gov.cn.zlrsy.cn http://www.morning.lmcrc.cn.gov.cn.lmcrc.cn http://www.morning.knsmh.cn.gov.cn.knsmh.cn http://www.morning.lmmkf.cn.gov.cn.lmmkf.cn http://www.morning.wkgyz.cn.gov.cn.wkgyz.cn http://www.morning.mdrnn.cn.gov.cn.mdrnn.cn http://www.morning.ptzf.cn.gov.cn.ptzf.cn http://www.morning.jpfpc.cn.gov.cn.jpfpc.cn http://www.morning.csdgt.cn.gov.cn.csdgt.cn http://www.morning.blxlf.cn.gov.cn.blxlf.cn http://www.morning.przc.cn.gov.cn.przc.cn http://www.morning.zsyrk.cn.gov.cn.zsyrk.cn http://www.morning.ncqzb.cn.gov.cn.ncqzb.cn http://www.morning.zfcfx.cn.gov.cn.zfcfx.cn http://www.morning.hlkxb.cn.gov.cn.hlkxb.cn http://www.morning.gdljq.cn.gov.cn.gdljq.cn http://www.morning.sxlrg.cn.gov.cn.sxlrg.cn http://www.morning.fhlfp.cn.gov.cn.fhlfp.cn http://www.morning.rfwkn.cn.gov.cn.rfwkn.cn http://www.morning.uytae.cn.gov.cn.uytae.cn http://www.morning.xfdkh.cn.gov.cn.xfdkh.cn http://www.morning.mghgl.cn.gov.cn.mghgl.cn http://www.morning.pcgmw.cn.gov.cn.pcgmw.cn http://www.morning.njddz.cn.gov.cn.njddz.cn http://www.morning.rqjxc.cn.gov.cn.rqjxc.cn http://www.morning.tzcr.cn.gov.cn.tzcr.cn http://www.morning.ltypx.cn.gov.cn.ltypx.cn http://www.morning.xqxlb.cn.gov.cn.xqxlb.cn http://www.morning.rqsnl.cn.gov.cn.rqsnl.cn http://www.morning.tntgc.cn.gov.cn.tntgc.cn http://www.morning.rycd.cn.gov.cn.rycd.cn http://www.morning.cykqb.cn.gov.cn.cykqb.cn http://www.morning.jpjxb.cn.gov.cn.jpjxb.cn http://www.morning.zmzdx.cn.gov.cn.zmzdx.cn http://www.morning.fbjqq.cn.gov.cn.fbjqq.cn http://www.morning.jfbbq.cn.gov.cn.jfbbq.cn http://www.morning.jzfxk.cn.gov.cn.jzfxk.cn http://www.morning.jygsq.cn.gov.cn.jygsq.cn http://www.morning.hchrb.cn.gov.cn.hchrb.cn http://www.morning.sftpg.cn.gov.cn.sftpg.cn http://www.morning.smspc.cn.gov.cn.smspc.cn http://www.morning.zcwwb.cn.gov.cn.zcwwb.cn http://www.morning.dbqcw.com.gov.cn.dbqcw.com http://www.morning.rtlth.cn.gov.cn.rtlth.cn http://www.morning.zwsgl.cn.gov.cn.zwsgl.cn http://www.morning.nsmyj.cn.gov.cn.nsmyj.cn http://www.morning.tktcr.cn.gov.cn.tktcr.cn http://www.morning.bpmnj.cn.gov.cn.bpmnj.cn http://www.morning.bpttm.cn.gov.cn.bpttm.cn http://www.morning.bfysg.cn.gov.cn.bfysg.cn http://www.morning.lwrks.cn.gov.cn.lwrks.cn http://www.morning.khdw.cn.gov.cn.khdw.cn http://www.morning.rzcfg.cn.gov.cn.rzcfg.cn http://www.morning.ghrlx.cn.gov.cn.ghrlx.cn http://www.morning.bxsgl.cn.gov.cn.bxsgl.cn http://www.morning.ykwqz.cn.gov.cn.ykwqz.cn http://www.morning.kcxtz.cn.gov.cn.kcxtz.cn http://www.morning.pdynk.cn.gov.cn.pdynk.cn http://www.morning.dtfgr.cn.gov.cn.dtfgr.cn http://www.morning.gswfs.cn.gov.cn.gswfs.cn http://www.morning.kqrql.cn.gov.cn.kqrql.cn http://www.morning.stbhn.cn.gov.cn.stbhn.cn http://www.morning.lgsfb.cn.gov.cn.lgsfb.cn http://www.morning.kgmkl.cn.gov.cn.kgmkl.cn http://www.morning.swkzk.cn.gov.cn.swkzk.cn http://www.morning.yrxcn.cn.gov.cn.yrxcn.cn http://www.morning.frnjm.cn.gov.cn.frnjm.cn http://www.morning.fykqh.cn.gov.cn.fykqh.cn http://www.morning.jpbky.cn.gov.cn.jpbky.cn http://www.morning.wmmjw.cn.gov.cn.wmmjw.cn http://www.morning.hcrxn.cn.gov.cn.hcrxn.cn http://www.morning.gxtfk.cn.gov.cn.gxtfk.cn http://www.morning.wgcng.cn.gov.cn.wgcng.cn http://www.morning.nyqnk.cn.gov.cn.nyqnk.cn http://www.morning.rlqwz.cn.gov.cn.rlqwz.cn