幂等思路

前端设计

按钮设置点击一次

按钮设置只可以点击一次。多次点击无效

设置token

token机制。进入页面获得token,发送请求携带token。

重定向

点击提交后,客户端重定向。

session

服务端生成唯一标识,存入session中,同时写入表单隐藏域。提交时同时提交,与session中的进行比较。相同移除session中的唯一标识,进行后续操作,不相等标识重复提交,不做处理。

后端设计

唯一索引

设置唯一索引,重复插入数据库报异常。不会生成脏数据

token+ redis

分两个阶段:申请token阶段和业务操作阶段
例如支付:

  • 首先,在进入提交订单页面之前,订单系统根据用户信息向支付系统发送token申请,支付系统将生成的token保存到redis缓存中
  • 然后,订单系统带着token去发起支付请求,支付系统对比redis中的token,存在,执行支付逻辑,删除token,不存在标识非法请求。
设置多个状态

例如订单设置status有多个状态,待支付,支付中,支付完成等状态,根据状态更新。

乐观锁

先查询得到锁,更新数据同时更新锁。
例如:version = 1 ,更新时version+1,再次更新时version=1就会更新失败。

分布式锁
### 等性概述 等性是指某个操作可以多次执行而不会改变其最初的效果。具体来说,在编程和API设计中,如果一个请求被重复发送,无论发送多少次,最终的结果都应该是相同的,并且资源的状态也不会因为重复调用而发生额外变化[^2]。 ### API 设计中的等性重要性 对于网络服务而言,由于互联网环境存在诸多不确定性因素,客户端可能会遇到超时、断网等问题从而导致请求失败或不确定状态。此时为了保证业务逻辑的一致性和数据的安全可靠,就需要引入等机制来处理这类情况。当用户再次发起相同的操作时,服务器端能够识别这是同一个事务的不同尝试而不是新的独立事件,进而做出恰当响应而不影响实际效果[^3]。 ### 实现等性的几种方式 #### 使用防重Token令牌方案 一种常见的做法是在每次提交表单或者发出特定类型的HTTP请求之前生成唯一标识符作为token存放在缓存里;之后随同其他参数一起传给后台接口用于验证合法性以及判断是否已经成功处理过此条记录。一旦确认无误,则立即删除对应的key-value对防止后续可能存在的冲突风险[^4]。 ```java // Maven 引入相关依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> // 防重Token 令牌实现伪代码 public boolean checkAndSet(String key){ try{ // 尝试设置新值并返回旧值 String oldValue = redisTemplate.opsForValue().getAndSet(key,"1"); if (oldValue != null && !"0".equals(oldValue)){ log.info("Duplicate request detected."); return false; } // 设置失效时间以确保长时间未完成的任务自动清理 redisTemplate.expire(key, expireTime, TimeUnit.SECONDS); return true; }catch(Exception e){ throw new RuntimeException(e.getMessage()); } } ``` #### 利用数据库特性 另一种思路是利用关系型数据库提供的原子性更新语句(如MySQL里的`INSERT ... ON DUPLICATE KEY UPDATE` 或者 PostgreSQL 的 `UPSERT`) 来达成目的。这种方式适用于那些天然具有唯一约束条件的数据模型场景下,比如订单号、交易流水号等等[^5]。 ```sql -- MySQL 插入或更新示例 INSERT INTO orders(order_id,status) VALUES('unique_order_007','PENDING') ON DUPLICATE KEY UPDATE status=VALUES(status); -- PostgreSQL UPSERT 示例 INSERT INTO orders(order_id,status) VALUES('unique_order_008','COMPLETED') ON CONFLICT (order_id) DO UPDATE SET status=EXCLUDED.status; ``` #### 基于框架特性的解决方案 某些流行的Web开发框架也内置了支持等功能的工具集,例如Spring AOP可以通过面向切面编程的方式轻松地为指定的服务层方法添加等控制逻辑。只需简单配置几个注解就能让整个流程变得既简洁又高效。 ```python from spring.aop import idempotent @idempotent def withdraw(account_id: int, amount: float) -> bool: """模拟提款功能""" pass ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值