一、什么是幂等
先看度娘是怎么说的: 幂等 (idempotent、idempotence)是一个数学与计算机学概念,常见于 抽象代数 中。
在编程中一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些 函数 不会影响系统状态,也不用担心重复执行会对系统造成改变。例如,“setTrue()”函数就是一个 幂等 函数,无论多次执行,其结果都是一样的.更复杂的操作幂等保证是利用唯一交易号(流水号)实现。
幂等性: 多次调用方法或者接口不会改变业务状态,可以保证重复调用的结果和单次调用的结果一致。
幂等性接口: 是指可以使用相同参数重复执行,并能获得相同结果的接口。
二、防重与幂等的区别:
防重的设计主要是为了避免产生重复的数据,对接口的要求没有太多;
幂等性设计除了是为了避免产生重复的数据,还要求每次请求返回一样的结果;
防重技术手段一般有这样几种方案:
在客户端进行去重;在接口层面进行去重;在数据库设计方面进行限定;
幂等性的实现方式下面会具体说明。
三、实现接口幂等性的几种方式
1、先查询再判断
insert前先进行select操作,如果不存在则insert,如果已经存在,则update。
但此种方案不适合高并发的场景。
2、加唯一索引
数据库表建立了唯一索引之后,可以保证最终插入的数据只有一条数据,之后的请求相同则会报唯一索引冲突。
在表上创建一个唯一的 索引 。唯一的索引意味着两个行不能拥有相同的索引值。
CREATE UNIQUE INDEX index_name ON table_name (column_name)
3、建立防重表
有些场景允许有重复的数据,只有某些特定的场景不允许,这种时候加唯一索引显然不合适,可以采用增加防重表。
客户端发送请求—–首先插入到 mysql 防重表—-判断是否成功,成功后再进行其他操作;失败则会报唯一索引冲突。
注意:此种防重表与业务表必须存在于同一个数据库中,并且操作同一事务。
4、根据状态位来进行处理
比如在业务表中增加状态位:1-下单、2-已支付、3-待支付、4-已完成、5-撤销。
可根据状态位进行判断,仅限于更新有状态位的表。
5、token令牌的方式
比如用户登录时会生成token,服务端将token存入 redis ;
客户端在进行其他接口请求时会在 header 中携带从服务端获取的token进行访问,服务端会对携带的token进行验证。如果token存在则进行下一步操作。
6、加悲观锁
通过加排它锁来实现,如:select * from tb1 where name=’dog’ for update
此时的where字段必须加索引,不然会造成锁表。有时由于表不大,mysql的索引优化器,优化之后 sql 不走索引,结果也会造成锁表,这里要特别注意一下。
但加悲观锁一般适合防重的场景,并不适合高并发以及幂等场景。
7、加乐观锁
悲观锁存在性能的问题,为了提升性能,可以考虑使用 乐观锁 来进行实现。
需要在表中增加版本号version或者时间戳temestap字段来实现。
乐观锁存在失效的情况,也就是ABA的问题,但是一般我们的version版本都是递增的不会出现此问题。
8、加分布式锁
可以使用redis或者 zookeeper 来作为分布式锁的实现方式。
具体可以参考文章:简单解析分布式锁的三种实现方式
注:分布式锁一定要设置合理的过期时间,过短也会造成重复数据,过长则会造成redis存储空间的浪费。

