什么是幂等性?
接口幂等性就是用户对于同一操作发起的一次请求或者多次请求的结果是一致的,不会因为多次点击而产生了副作用。比如:公交车刷卡,用户上车后刷码支付扣款成功,如果用户再次点击按钮刷卡并扣款成功,用户查询余额返发现多扣钱了,流水记录也变成了两条,这就没有保证接口的幂等性。因此,当你重复刷卡时,会提示:刷码重复。
注意:数据库可能产生幂等性问题,但是幂等性问题不只发生在数据库。
什么场景需要幂等设计?
一般对数据要求比较高的场景,如:金钱交易、数据一致性至关重要的业务场景:
在线支付:当用户发起支付请求时,避免重复扣款。
银行交易:确保同一笔交易不会因网络重试等原因被执行多次。
票务系统:在线购票平台在用户购票时,检查所选座位是否已被重复预订。
通信服务:如短信或通话服务,系统会检查是否已为相同内容的请求计费。
任务调度:在定时任务或批处理系统中,确保不会因为任务重启或重试而重复执行相同的操作。
用户注册:防止因重复提交表单而导致用户信息被创建多次。
如何产生幂等问题?
产生幂等性问题的原因主要有:
网络请求重试:网络波动或超时,客户端可能会重复发送相同的请求。
用户界面重复提交:用户在用户界面上可能会不小心重复点击按钮,导致相同的请求被发送多次。
消息队列重试机制:使用消息队列(如Kafka、RabbitMQ)时,消息可能会被重复消费。
数据库并发操作:数据库的插入、更新和删除操作多个事务同时修改同一条记录,而没有使用适当的锁机制或事务隔离级别。
外部系统API接口重试:对外提供的API接口可能由于调用方的重试逻辑,导致数据库操作被重复调用。
其它......
下面我们简单做些案例说明。
表设计(前期准备)
我们先来设计一张订单表并模拟一些数据:
1、表结构:
2、字段说明:
order_id:作为订单的唯一标识,通常是一个全局唯一的ID,如使用UUID或分布式ID生成器(如Snowflake算法)生成。
user_id:标识下单的用户,用于关联用户信息。
product_id:标识被购买的商品,用于关联商品信息。
quantity:购买的商品数量。
order_status:订单当前状态,用于控制订单的业务流程,确保幂等性。例如,只有当订单状态为“待支付”时,支付操作才会被执行。
create_time:记录订单创建的时间戳。
pay_time:记录订单支付的时间戳,如果订单被支付,这个字段会被更新。
version:乐观锁的版本号,每次更新操作都会增加该字段的值,用于检测在业务处理期间订单是否被其他事务更新过。
3、业务规则:
订单支付:在支付操作前,先检查order_status是否为“待支付”,若是,则执行支付逻辑,并更新order_status为“已支付”;如果不是,则拒绝支付,保持订单状态不变。
订单取消:在取消操作前,同样检查order_status,只有订单在特定状态下才允许取消操作。
插入订单:使用order_id作为唯一约束,防止重复插入相同订单。
乐观锁:在更新订单状态时,使用version字段来确保在读取和更新之间没有其他事务更改了订单,如果读取的version和数据库中的version不一致,则拒绝更新。
4、数据状态