浅聊幂等

Posted 孤舟浪天涯

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了浅聊幂等相关的知识,希望对你有一定的参考价值。

一、幂等的本质。

    幂等的本质就是请求执行一次和重复执行多次的结果相同

即:f...f(f(x)) = f(x)

       x表示请求参数

        f表示执行的方法

二、哪些场景下会遇到幂等问题

场景一:用户转账重试

    如果A给B转账,A的转账请求超时,A的服务会请求重试。

    这是技术上的幂等问题,因为分布式请求有重试机制导致的。

场景二:不能重复下单

    同一个用户在一定时间内只能下单一次

    这是一个业务上的幂等问题,用户可能在短时间内重复提交相同的数据

    (例如连续点击保存按钮)。

三、什么时候需要做幂等

1、从请求类型上看

     由于读请求不会对数据发生改变所以不需要做幂等控制。

     update,insert,delete改变数据的请求才需要做幂等控制

2、从架构层面看

     由于代理层、网关层、业务逻辑层不会对数据发生改变所以不需要做幂等控制。

     只有数据访问层和DB层会操作数据才需要做幂等控制

四、如何做幂等

1、对要求唯一的一个或多个字段建立unique index。

     例如:品牌表里的name不能重复,则用name建unique index。

2、如果一个表里的字段可以为0/null或其它唯一值,则可以新建一个表仅包含有唯一约束的字段并将该字段设置unique index。只将该字段不为0/null的数据插入该表,若出现重复的非0/null值则会事务回滚。

     例如:产品信息官方产品也可以是自定义产品,official_id是对应的官方产品Id,如果是自定义的产品则official_id为0。在这种场景下为了保证官方产品的不重复可以新建一个official_id_unique表,包含official_id字段并建立unique index。在同一个事务当插入官方产品信息时同时向该表插入official_id字段

 @Transaction public void saveProduct(Product product){ insert(product);     if(!product.getOfficialId().equal(0)){ insertOfficialId(product.getOfficialId());     }  }

3、对于无法设置unique index的数据如何保证不会出现幂等问题?

     对于mysql来说都会生成一个主键索引而且主键索引字段必须是唯一的。如果主键Id不是自增Id而是跟新增的业务数据同步生成那么就可以保证每次新增的业务数据不会重复插入

例如:订单表结构为

order{

    uuid int,

    order_on int,

    product_id int

     ...

 }

客户在下单的时候在前端页面产生一个订单主键order_uuid,那么客户在保存订单数据时即使是前端请求超时重试,因为有order_uuid的唯一约束也不会重复插入订单数据。

在大多数据情况下不建议使用增Id,主要有以下几个原因:

(1)业务数据保密(根据自增Id可以了解业务数据增长情况)

(2)在做单据和明细数据插入时,明细数据需要包含单据的Id 如果自增Id,单据只能循环插入。

(3)自增Id不好做幂等控制。

 4、业务幂等问题如何解决?

     如何避免用户重复点击导致数据重复插入,只需在数据没有修改的情况下保证uuid不变就可以了。

    同一个数据库的数据操作可以通过设置唯一主键,通过数据库事务保证数据一致性。对于需要跨库操作的数据怎样保持数据一致性呢?

例如:操作1:付款

          操作2:改变单据状态

    操作1和操作2是两个链式操作,操作1执行成功之后再去执行操作2,如果操作1失败这时是没问题的,应为操作2不会执行。但是如果操作1成功,操作2失败就会有问题了,钱已经付了,订单还是未付款。付款和修改订单状态是对两个数据库的操作保证原子性和一致性的要求,这就需要用到分布式事务了改日再单独聊。

以上是关于浅聊幂等的主要内容,如果未能解决你的问题,请参考以下文章

浅聊JavaScript中的this

浅聊java编程建模之UML

ACM浅聊

Kubernetes——浅聊 Affinity,就这么点东西

浅聊ArrayList

架构师初码邀你—浅聊上云思路