生产问题-并发重复生成订单(幂等性)问题

运营发现重复订单,源于核心代码并发问题。解决策略包括移除最外层事务,采用分布式锁控制事务,保证一致性;利用唯一ID、数据库约束、乐观锁、分布式锁工具、Token机制和幂等框架来防止重复操作。具体选择取决于系统需求和架构设计。
摘要由CSDN通过智能技术生成

情景回顾

某天运营同事发现管理后台生成了两条重复的订单,反馈到技术部门进行紧急排查。

伪代码分析

通过排查代码发现,发现核心代码有并发问题,根据事务传递性锁中的事务无法独立生效,所以锁释放时事务并没有提交,此时新的请求获得锁时查询到的数据依然是更新前的数据,故锁没有起到应有的效果。
代码如下:

	@Override
    @Transactional(rollbackFor = Exception.class)
    public void addOrder(User user) {
        RLockTemplate.lockGet(user.getUserId(),()->{
            //进行生成订单操作 insert into t_order
            saveOrder(user.getUserId());//这个方法底层也有事务
            return true;
        });
        //保存日志 insert into t_log
        saveLog(user.getUserId());
    }

在这里插入图片描述

解决方案

这里去掉最外层的事务,将事务放在分布式锁里面。

解决幂等性问题总结建议

事务应该在分布式锁的里面进行控制。首先获取分布式锁保证在分布式环境中相关操作的原子性和一致性,之后在锁的保护下进行事务操作,这样可以确保在并发环境下,对共享资源的访问和修改是安全的,操作完成后再释放分布式锁。如果把事务放在分布式锁的外面,则无法保证事务内的操作在并发场景下的安全性和一致性。

其他:

  1. 唯一事务号或ID:
    API调用时传递一个唯一标识符(比如UUID或数据库自增ID),服务端对这个ID做校验和记录,确保相同ID的请求只被执行一次。

  2. 数据库唯一约束:
    在数据库表中设置唯一约束或索引,可以防止相同的记录被插入多次。

  3. 乐观锁:
    在数据表中使用版本号或时间戳字段,当进行更新操作时检查这个版本号是否变化,若没变化则允许更新,否则拒绝,以此避免数据重复操作。

  4. 分布式锁:
    使用类似Redis、ZooKeeper这样的分布式锁工具,在执行关键部分前获得锁,确保分布式环境中同时只有一个线程能操作共享资源。

  5. Token机制:
    服务端生成一个Token返回给客户端,客户端执行操作时携带这个Token,服务端通过Token来识别请求,执行成功后Token失效,确保请求只被执行一次。

  6. 幂等框架:
    使用一些成熟的框架比如Idempotent、Spring Retry等,可以直接在方法上添加注解来实现幂等性,无需自己实现复杂的逻辑。

  7. 消息队列:
    使用消息队列确保消息消费的幂等性,比如Kafka等持久化消息,配合消息的offset实现消息处理的幂等性处理。

具体使用哪种方案取决于系统的需求和架构设计。一些方案可能要与业务紧密结合,有些则可以通过中间件来解耦实现。

  • 6
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值