幂等,在计算机中表示对同一个过程应用相同的参数多次和应用一次产生的效果是一样,这样的过程即被称为满足幂等性在分布式和前后端分离的项目中,对于 restful风格的接口,我们需要保证其接口的幂等性,说白了就是一个接口被反复调用不会影响最终结果;为什么呢,因为前后端分离的项目可能会发生这样的场景:前端发出一个请求,但这个请求被阻塞了,然后其重试机制再次发起请求,而恰好此时被阻塞的那个请求又好了,那么这个时候,会对后端发起连续两次请求;对于 get,put,delete 都没有问题,连续的两次或者三次都不会影响请求处理结果,但 post 就有问题了;它会往数据库插入两条数据。

  这显然不是正确的处理结果。在分布式和前后端分离的项目中,前端数据对后端来说都是不可信的。因此有一个机制来保证接口的幂等性是很有必要的。按照 restful 规范定义的接口,使用http 方法,应该严格遵循 http 方法语义:方法幂等性对应 CRUD 操作 POST 不安全且不幂等、 CGET 安全且幂等 、RPUT不安全但幂等、UDELETE不安全但幂等

  幂等实现方法:

  使用全局唯一ID:(数据库唯一索引,或者 redis 保存一个key)就是根据业务的操作和内容生成一个全局 ID,在执行操作前先根据这个全局唯一 ID是否存在,来判断这个操作是否已经执行。如果不存在则把全局 ID存储到存储系统中,比如数据库、Redis等。如果存在则表示该方法已经执行。使用全局唯一 ID是一个通用方案,可以支持插入、更新、删除业务操但是这个方案看起来很美但是实现起来比较麻烦,下面的方案适用于特定的场景,但是实现起来比较简单。

  去重表:这种方法适用于在业务中有唯一标的插入场景中,比如在以上的支付场景中,如果一个订单只会支付一次,所以订单ID可以作为唯一标识。这时,我们就可以建一张去重表,并且把唯一标识作为唯一索引,用以记录订单支付信息,在我们实现时,把创建支付单据和写入去重表,放在一个事务中,如果重复创建,数据库会抛出唯一约束异常,操作就会回滚。这个方法其实也是用到唯一ID,与上面全局唯一ID不同的是,他是针对具体单个业务流程的,实现起来相对简单。

  版本控制:对数据库表加入版本号形成乐观锁,更新操作时必须拿到正确的版本号才能更新成功。