幂等和非幂等的区别

前两天,在日常工作的接口测试中,发现了一个现象,点击web页面里面表格显示的一个查询按钮时,它的接口路径还是没变,当时感到奇怪,
一般情况下,在web页面中,每一个可点击的地方都有可能时一个新的接口,也就是一个新的url,至少url的后缀是会有变化的;今天还是头一次碰到这种现象,而且是put请求的接口;
我就很纳闷了,查询接口一般都是get请求的,这里为什么还用了put请求呢?后来在网上查了一下,原来是涉及到幂等的知识;所以今天咱就捋一捋这块的知识点:
一、幂等的概念
幂等:多次重复操作和一次操作产生的影响是一样的;
非幂等:多次重复操作和一次性操作产生的影响是不一样的;
通俗点讲:就是你调用的这个接口(前端的这个按钮),后台都返回同样的数据,并且不会修改状态信息,接口可重复调用,一次或者多次都是一样的数据。
注意:这里强调的是产生的影响是一样的,而不是结果一样。就拿最常见的增删改查的业务,一个新增接口add;比如你一次插入请求插入一条数据,产生的影响是多一条记录,
后台业务层在没有返回显示新增成功之前;哪怕你多次插入请求产生的影响如果产生的影响也是多一条数据,那么就是幂等的,而不是说一次插入的一条数据和多次插入的数据结果一样。
二、什么业务场景使用幂等性
2.1案例一:举个最简单的例子,就是平时的手机支付,用户购买商品支付购买,支付扣款成功,但是返回结果的时候网络异常,后台那边钱已经扣了,用户并不知道,因为网络原因没推送回来扣款成功的消息,
如果用户再次点击按钮,平台如果进行第二次扣款,且返回结果成功,用户查询余额返发现多扣钱了,流水记录也变成了两条。这就不合理了;用户明明只需要付一笔支付就行,
虽然动作执行了2次,但产生的影响是一样的,即理论上只应该扣一次钱就行;这里就要用到幂等;如果没用幂等很有可能会造成扣款2次的情况发生。
2.2一般有以下几种场景会用到:
①我们发起一笔付款请求,应该只扣用户账户一次钱,当遇到网络重发或系统bug重发,也应该只扣一次钱;
②发送消息,也应该只发一次,同样的短信发给用户,用户会哭的;
③创建业务订单,一次业务请求只能创建一个,创建多个就会出大问题等等很多重要的情况都需要幂等的特性来支持。
④火车票出票,购票成功,还在等待中,及时网络异常,多次点击,最终出来的还是一张票,不会出来很多张票。
由此可见:在设计系统时,幂等是首要考虑的问题,尤其是在像支付宝,银行,互联网金融公司等涉及的都是钱的系统,既要高效,数据也要准确,
所以不能出现多扣款,多打款等问题,会极度的影响用户体验,会被投诉,甚至会吃官司。
三、技术方面如何来实现幂等
1、可以通过http协议(超文本传输协议):来区分。get,put,delete是天然的幂等操作,所以在尽量使用这些方法。
幂等的:get、put、delete
非幂等的:post、patch
2、建立唯一索引,能防止新增的脏数据,比如在银行的账户中,每个支付宝的资金账户,支付宝也有用户账户,每个用户只能有一个资金账户,怎么防止给用户创建银行账户多个,那么给账户表中的用户ID加唯一索引,
所以一个用户新增成功一个资金账户记录。要点:唯一索引或唯一组合索引来防止新增数据存在脏数据(当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可)。
3、token + (redis) 的机制(token的特点 : 一次有效性,时效性,可以对流量进行控制),可以防止页面的重复提交。具体实现 : 发生的原因由于重复的点击 , 网络原因导致了多次发送请求,
或者由于nginx重发等情况会导致数据被重复的提交 ; 解决的方案 :在数据提交给后台服务器处理时,要向服务器申请token(全局唯一的变量),将token存放到redis(可以是其他的)中,设置token的有效时间。
当服务器接受到请求进行处理时,对token进行校验,校验通过后并删除该token,并生成新的token返回
4、悲观锁和乐观锁:
悲观锁 : 更新数据时认为此次操作会造成数据的缺失。
注意 : id字段必须时主键或者唯一索引,不然的话就锁了整个表,导致效率降低,必须开启事务,缺点容易造成死锁,不建议使用
乐观锁 : 更新数据时认为此次操作不会造成数据缺失,所以只是在更新数据那一刻锁表,其他时间不锁表,相对于悲观锁的效率更高。
实现方式 : 在数据库的表中增加一个字段version(版本号)或者是其他的状态位。在对表进行操作时同时取出数据和标志位version,当要修改数据表时,对version进行判断是否与之前取出的一致,如果一致则修改,
如果不一致则不修改。同时version自增一存入数据库。(注意 : 注意:乐观锁的更新操作,最好用主键或者唯一索引来更新,这样是行锁,否则更新时会锁表)
5、分布式锁,加入系统部署在分布式系统上,构建全局的唯一索引比较困难(唯一的字段无法没法确定),这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,
获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,
也就是分布式系统中得解决思路要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,
执行完成后,释放分布式锁(分布式锁要第三方系统提供);
6、状态机制,在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,
这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。

总之幂等性,是最符合用户使用的逻辑的,也是不会轻易出错的,特别是在金融,银行等涉及到交易支付的行业。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章