Ruby on Rails钱包交易API并发请求下transaction_id重复问题求助
Rails钱包交易API并发重复记录问题解决思路
问题场景
基于Ruby on Rails开发的钱包交易创建API,因对接多家银行、交易创建逻辑复杂,最初未在模型层给transaction_id/reference_no加唯一性验证。原本通过before_action检查同transaction_id的记录是否存在,存在则返回错误,但生产环境中遇到银行并发请求的情况,导致同一transaction_id生成了两条created_at完全相同的重复记录。
本地用Ruby脚本复现了该问题:Rails会同时处理两个请求,即便添加Active Record唯一性验证,两个请求的exists?查询会同时执行且都返回nil,最终还是创建了重复记录。
现有约束
理论上数据库级唯一性约束是根治方案,但当前有近15个生产数据库,部分库中可能已存在重复记录,且该模块属于系统敏感部分,直接加约束风险较高,因此需要寻找更稳妥的并发处理方案。
已尝试无效方案
- 添加模型层唯一性验证
- 使用Ruby的
Mutex锁(进程内有效,多进程部署下失效) - 采用MySQL的
GET_LOCK锁(仅单实例有效,多数据库/多实例场景下失效)
可行解决方案探讨
1. 先清理重复数据,逐步添加数据库约束
这是最彻底的方案,步骤如下:
- 编写批量脚本,遍历所有生产数据库,找出
transaction_id重复的记录,结合业务规则(比如保留状态正常、最新创建的记录)清理重复数据 - 清理完成后,分批给数据库添加唯一性约束(可先通过
ALTER TABLE ... ADD UNIQUE INDEX ... IGNORE的方式创建,避免因遗留数据报错) - 同时在模型层添加
validates :transaction_id, uniqueness: true,形成模型验证+数据库约束的双重保障,从根源避免重复
2. 事务+悲观锁控制并发
在创建交易的逻辑中,用数据库事务包裹,并配合悲观锁让并发请求排队执行:
WalletTransaction.transaction do # 通过FOR UPDATE锁定该transaction_id的查询范围,即使无记录也会锁定,阻止其他请求的同条件查询 WalletTransaction.where(transaction_id: params[:transaction_id]).lock(true).first # 再次检查是否存在记录 if WalletTransaction.exists?(transaction_id: params[:transaction_id]) raise ActiveRecord::Rollback, "重复交易请求" end WalletTransaction.create!(transaction_id: params[:transaction_id], ...) end
这种方式利用数据库事务的隔离性,确保同一transaction_id的创建请求串行执行,避免重复。
3. 分布式锁(多实例/多数据库场景)
如果是多服务器部署或多数据库实例的情况,进程内锁和单数据库锁都无效,可采用Redis分布式锁:
lock_key = "wallet_transaction_lock:#{params[:transaction_id]}" # 设置锁超时时间,避免死锁 lock = Redis.current.lock(lock_key, expires_in: 10.seconds) begin if lock.acquire # 锁获取成功,执行创建逻辑 unless WalletTransaction.exists?(transaction_id: params[:transaction_id]) WalletTransaction.create!(...) else # 返回重复错误 end else # 锁获取失败,说明有并发请求在处理,直接返回重复提示 end ensure # 确保锁被释放 lock.release if lock end
分布式锁可以跨进程、跨服务器控制并发,适合复杂部署场景。
4. 基于幂等性的请求处理优化
在API层面强化幂等性设计:
- 要求对接的银行端以
transaction_id作为幂等键,确保同一交易的重复请求不会触发重复创建 - 服务端收到请求后,先在Redis中记录该
transaction_id的处理状态(比如"处理中"),并发请求过来时,若发现状态为"处理中"则等待或直接返回已有结果;处理完成后更新状态为"完成" - 结合数据库查询,双重验证避免重复
内容的提问来源于stack exchange,提问作者M Ibtehaj Nasar
相关产品推荐
相关产品推荐

