幂等解决方法有哪些?

1 个回答

  • 元始大天尊
    忙碌足以冲淡很多复杂的情绪
    幂等性是指相同请求执行一次或多次所带来的副作用是一样的。在分布式系统中,保证接口的幂等性是非常重要的,因为网络问题或其他原因可能导致请求的重复提交。 #### 常见场景 - 前端调后端接口发起支付超时,重试导致多次支付。 - Dubbo等RPC框架中有重试机制。 - 页面上用户多次点击同一按钮。 ### 解决方案 #### 1. 插入去重表 在插入数据时,插入去重表,并利用数据库的唯一索引特性,保证数据的唯一性。 ```sql CREATE TABLE unique_requests ( id VARCHAR(255) PRIMARY KEY, request_data TEXT ); -- 插入数据时 INSERT INTO unique_requests (id, request_data) VALUES (?, ?); ``` #### 2. 悲观锁 使用 `SELECT ... FOR UPDATE` 语句,锁定订单对应的记录,确保整个执行过程中的幂等性。适用于DB读大于写的情况。 ```sql START TRANSACTION; SELECT * FROM orders WHERE order_id = ? FOR UPDATE; -- 执行业务逻辑 COMMIT; ``` #### 3. 先查询后修改数据 在并发不高的后台系统或一些任务JOB中,先查询关键数据,判断是否已经执行过,再进行业务处理。 ```java // 先查询是否已经执行过 Order order = orderService.findOrderById(orderId); if (order.getStatus().equals("PROCESSED")) { return; // 已经处理过 } // 处理业务逻辑 orderService.processOrder(order); ``` #### 4. 状态机幂等 在单据或任务相关业务中,设计状态机。如果状态已经处于下一个状态,拒绝重复变更,保证幂等性。 ```java public void updateOrderStatus(Order order, String newStatus) { if (order.getStatus().equals(newStatus)) { return; // 状态已经是目标状态 } // 更新状态 order.setStatus(newStatus); orderRepository.save(order); } ``` #### 5. Token机制防止重复提交 在数据提交前向服务申请token,token存储在Redis或JVM内存中,并设置有效时间。提交后校验token,同时删除token。 ```java // 生成token String token = UUID.randomUUID().toString(); redisTemplate.opsForValue().set(token, "valid", 5, TimeUnit.MINUTES); // 提交时校验token String token = request.getParameter("token"); if (redisTemplate.delete(token)) { // 处理业务逻辑 } else { throw new DuplicateSubmissionException("重复提交"); } ``` #### 6. 全局唯一ID 使用全局唯一ID,执行操作前检查ID是否存在,以判断操作是否已经执行过。如果不存在,则存储全局ID,并执行操作。 ```java String globalId = generateGlobalId(order); if (redisTemplate.opsForValue().setIfAbsent(globalId, "processed")) { // 处理业务逻辑 } else { throw new DuplicateSubmissionException("重复提交"); } ``` ### 总结 在实际开发中,根据具体业务场景选择合适的幂等性解决方案: - 数据库去重表适用于数据写操作较少且关键的数据插入操作。 - 悲观锁适用于DB读大于写的情况,但需注意性能问题。 - 先查询后修改数据适用于并发不高的后台系统。 - 状态机适用于需要状态变更的业务逻辑。 - Token机制适用于防止页面重复提交,确保接口幂等性。 - 全局唯一ID适用于业务操作需要全局唯一性的场景。
    发布于 2024-08-06 17:19 •IP属地 新疆
    举报
    评论
    收藏