一、何为幂等性
幂等性:幂等是一个数学与计算机学概念,常见于抽象代数中,表示N次变换和1次变换的结果是相同的。在编程中,一个幂等操作的特点是其任意多次执行所产生的影响均与一次执行的影响相同。幂等函数,或幂等方法,是指可以使用相同参数重复执行,并能获得相同结果的函数。这些函数不会影响系统状态,也不用担心重复执行会对系统造成改变。
二、问题的思考
今天看到了一个问题:如何保证对外接口的幂等性?
其实,幂等和是不是分布式高并发并没有直接的关系,在于你的操作是不是幂等的。在我们平时日常开发中,无外乎就是增删改查,查询类就不必说了,具有天然的幂等性。删除操作也是幂等的,删除一次和删除多次都是将这条数据删除。
在我们开发的场景中,其实就是在某些情况下,客户端调用服务没有达到预期效果,会多次调用接口,为了避免这种重复调用对服务资源产生副作用,开发的接口需要保证幂等性。
举个栗子,如果客户在使用支付功能时,因为网络或者其他原因,支付接口多次调用,用户看到自己同一笔交易付了那么多次钱,心凉了半截儿,一会就得去投诉你了。
三、应对方法
方法1:去重表(适用于特定场景,实现起来较为简单)
适用于业务中有唯一标的插入场景,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,可以建立一张去重表,并且把唯一标识作为唯一索引,在我们实现时,把创建支付单据和写入去去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束一场,操作就会回滚。
方法2:参考乐观锁:通过标识或其他字段对update限制。
每次拿到当前某个标识,在修改的时候把这个标识作为条件,通过这个标识条件,判断记录是否已经产生了变化。这个标识可以是时间戳,版本号字段,等等。
方法3:参考悲观锁:获取数据时加锁
悲观锁使用时会伴随着事务进行,但是可能会导致锁定时间较长。
方法4:Token
原理上来说,是通过session token来实现,当然也可以通过redis来实现,目前我所参与的项目用的就是后者。当客户端请求页面时,服务器会生成一个全局唯一的token,然后将该token放置到redis中,再将token发送给客户端。等下一次客户端提交请求,这个token就会和表单一起发送到服务器端。当服务器验证初次通过之后呢,就将这个token更新或者删除,如果用户重复提交,也就是第二次提交,验证判断就会失败,请求的操作也就不会重复执行了。
方法5:先查询后修改
对于并发不大的后台系统可以采取这种方式。