幂等性,是指函数/接口可以使用相同参数重复执行,这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。简单来说,就是任意多次执行所产生的影响均与一次执行所产生的影响相同。用户不会因为多次点击/调用而产生了副作用。这里的副作用是指不会对结果产生破坏或产生不可预料的结果。
HTTP 哪些方式是幂等的?
HTTP GET方式用于获取资源,不应有副作用,所以是幂等的。
比如:GET http://www.52jiagou.com/content/100 不会改变资源的状态,不论调用一次还是N次都没有副作用。这里说的是一次和N次的副作用,而不是每次GET的结果相同。虽然每次得到的结果不同,但它们本身并没有产生任何副作用,因而是满足幂等性的。
HTTP DELETE方法用于删除资源,有副作用,但它应该满足幂等性。
比如:DELETE http://www.52jiagou.com/del/100,删掉id=100的文章,因此调用者可以多次调用或刷新页面而不必担心引起错误。如果是删除,第一次删掉了3条,第二次删掉了5条记录,那就不是幂等。
HTTP POST不具备幂等性。
比如创建文章,两次相同的请求会创建两篇文章,所以POST方法不具备幂等性。
HTTP PUT创建或更新资源,具有幂等性。
因为没有就新建,有就修改,始终是对同一个资源进行操作。
场景:
1)网络波动,可能引起重复请求,导致插入了多次数据;
2)用户无意的触发多次下单多次交易,甚至没有响应而触发了多次交易;
3)第三方平台的接口,比如支付成功回调,因为异常导致多次回调;
4)页面重复刷新;
5)浏览器历史记录重复提交表单;
6)定时任务重复执行;
数据的幂等性
读:不需要做幂等
insert,用唯一索引来确保没有幂等性问题。
delete from A where id = 1;--幂等的
delete top (10) from A;--不是幂等的
update A set name='B' where id = 1--幂等的
update A set name = name + 'B' where id = 1--不是幂等的
后端幂等性的实现
1) 使用唯一索引防止新增脏数据;
2) Token+Redis幂等方案;
3) 状态机幂等;
4) 乐观锁实现幂等,通过版本号做乐观锁;
5) 缓冲队列,将请求放入队列,异步处理,过滤掉重复请求,有点是高吞吐,不足是不能及时返回请求,需要后续轮询查询处理结果。
总结:如果只用后端来做这个事的话,那么可以前端页面请求的时候在请求头加一个requestId,这个requestId在页面加载完成后由前端产生,每次刷新都要重新给requestId赋值,可以是一个随机的字符串,调接口的时候,先将这个requestId放到redis中,表明这个正在执行,如果这个时候同样的requestId进来,因为redis中已经存在,根据存放redis的值,返回重复执行的错误;在方法执行成功后,redis中写入执行成功,如果执行方法失败,则删除这个redis。 如果请求接口成功,页面是不刷新的,那么同样也是需要重置这个requestId。