接口设计如何保证幂等性

幂等(idempotent、idempotence)是一个数学与计算机学概念,常见于抽象代数中。

在编程中.一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同,例如:数据不变的情况下你去查同一个接口查一次和查多次返回的数据应该要一致,这就是幂等(select查询天然具有幂等)

保证幂等的方案

1.数据库唯一索引:
当表存在唯一索引,并发时新增报错时,再查询一次就可以了,数据应该已经存在了,返回结果即可
缺点:会增加对索引的维护开销,例如删除数据也要删除唯一索引,对于分库分表的系统可能不适用,需要额外的策略

2.悲观锁
例如:select * from table where id=#{id} for update;
注意:id字段一定是主键或者唯一索引,不然是会锁表的
悲观锁使用时一般伴随事务一起使用,数据锁定时间可能会很长,虽然实现简单但高并发场景不建议使用
3.乐观锁
乐观锁只是在更新数据那一刻锁表,其他时间不锁表,所以相对于悲观锁,效率更高。

乐观锁的实现方式多种多样可以通过version或者其他状态条件:
通过版本号实现

update table_xxx set name=#{name},version=version+1 where version=#{version}

4.token机制
token机制,防止页面重复提交
业务要求:
页面的数据只能被点击提交一次
发生原因:
由于重复点击或者网络重发,或者nginx重发等情况会导致数据被重复提交
解决办法:
集群环境:采用token加redis(redis单线程的,处理需要排队)
单JVM环境:采用token加redis或token加jvm内存
处理流程:

  1. 数据提交前要向服务的申请token,token放到redis或jvm内存,token有效时间

  2. 提交后后台校验token,同时删除token,生成新的token返回
    token特点:
    要申请,一次有效性,可以限流

    注意:redis要用删除操作来判断token,删除成功代表token校验通过,如果用select+delete来校验token,存在并发问题,不建议使用

5.分布式锁
还是拿插入数据的例子,如果是分布是系统,构建全局唯一索引比较困难,例如唯一性的字段没法确定,这时候可以引入分布式锁,通过第三方的系统(redis或zookeeper),在业务系统插入数据或者更新数据,获取分布式锁,然后做操作,之后释放锁,这样其实是把多线程并发的锁的思路,引入多多个系统,也就是分布式系统中得解决思路。

要点:某个长流程处理过程要求不能并发执行,可以在流程执行之前根据某个标志(用户ID+后缀等)获取分布式锁,其他流程执行时获取锁就会失败,也就是同一时间该流程只能有一个能执行成功,执行完成后,释放分布式锁(分布式锁要第三方系统提供)
6.通过状态机

在设计单据相关的业务,或者是任务相关的业务,肯定会涉及到状态机(状态变更图),就是业务单据上面有个状态,状态在不同的情况下会发生变更,一般情况下存在有限状态机,这时候,如果状态机已经处于下一个状态,这时候来了一个上一个状态的变更,理论上是不能够变更的,这样的话,保证了有限状态机的幂等。

注意:订单等单据类业务,存在很长的状态流转,一定要深刻理解状态机,对业务系统设计能力提高有很大帮助

你可能感兴趣的:(架构设计)