一、什么是幂等性
“幂等”是指一个操作重复执行N次得到的结果(副作用)与执行一次是相等的。
例如: 在HTTP协议中,get请求,会得到同样的数据
二、为什么需要幂等性
我们先从一个例子来说,假设 有一个远程取钱的API接口
bool get_money(id, amount)
参数:
id:用户的账户
amount: 表示取多少钱
返回值:
true: 表示取钱成功
false: 表示取钱失败
情景一:
1、一位用户A 取100块钱, 这个请求,发送到了服务器
2、服务器正常的处理了这个请求,把用户A的总额,减去了100块钱, 这时,服务器把处理结果返回给客户端。
3、服务器把处理结果,返回给客户端,可是这时,由于网络不稳定, 导致客户端没有接受到服务器返回的处理结果,这时,用户(或者客户端)进行重试,同样的请求又到服务器,服务器又在用户A的总额中,减去了100块钱........
用户A 取了100块钱, 银行却扣了 200.................
这个问题的解决方案是:
客户端在调用这个接口,传入一个流水号,
bool get_money(id, amount, serial_number)
对于同一个操作(同一笔业务)流水号不变(在不同操作中,必须保证流水号的唯一性),
这时,如果服务器遇到上面那种情况,只需要判断客户端传过来的这个流水号,是否已经操作(处理)过了,如果已经处理过了,就直接把处理结果返回给客户端
这样,就不存在上面的问题了
三、服务端,幂等性的实现误区
在服务端,一般情况下,对于每次请求,我们都会把 请求方、流水号、处理结果 存储在数据库中
如:
流水号 请求方 处理结果
20160311xxxx jiangxi0001 1
情景一:
1、客户端(请求方) jiangxi0002,过来一个请求,流水号是:20160311jiangxi0002xxxx
2、一般情况下,我们会先根据 ‘请求方’ 和 ‘流水号’ 取所在表查一下,看是否存在
3、假如,由于用户操作失误,服务端,同时接收到两个请求 A 和 B,请求A 和 请求 B的 ‘客户端(请求方)’ 和 ‘流水号’ 都相同。这时,两个请求同时处理,就可能碰到并发的问题了,导致这请求 A 和 请求 B 都向表中插了一条新的记录
解决方法:
在数据库中, 对 ‘请求方’ 和 ‘流水号’ 加唯一索引, 在请求来了之后,直接插入表,不进行查询操作,如果‘请求方’ 和 ‘流水号’已经存在,那么会插入失败, 这时我们再进行查询操作,确认是否已经存在,这样就能解决并发的问题了。