31 lines
1.2 KiB
MySQL
31 lines
1.2 KiB
MySQL
|
|
-- Settlement Withdraw Constraint v1.0
|
|||
|
|
-- 提现唯一约束说明
|
|||
|
|
--
|
|||
|
|
-- 问题: PRD 要求确保每个供应商同时只有一个 pending/processing 状态的提现
|
|||
|
|
--
|
|||
|
|
-- 解决方案: 在 repository 层使用 SELECT ... FOR UPDATE SKIP LOCKED
|
|||
|
|
-- 参见: internal/repository/settlement.go - CreateWithdrawTx()
|
|||
|
|
--
|
|||
|
|
-- 该方法在事务开始时锁定任何现有的 pending/processing 提现记录,
|
|||
|
|
-- 然后检查是否存在,如果不存在则插入新记录。
|
|||
|
|
--
|
|||
|
|
-- SQL 实现:
|
|||
|
|
-- 1. 首先执行: SELECT id FROM supply_settlements
|
|||
|
|
-- WHERE user_id = $1 AND status IN ('pending', 'processing')
|
|||
|
|
-- FOR UPDATE SKIP LOCKED
|
|||
|
|
--
|
|||
|
|
-- 2. 如果上面查询返回行,说明有 pending 的提现,返回错误
|
|||
|
|
--
|
|||
|
|
-- 3. 如果上面查询没有返回行(ErrNoRows),执行插入
|
|||
|
|
--
|
|||
|
|
-- 注意: 这个方案比使用辅助锁表更简单高效,因为:
|
|||
|
|
-- - 不需要额外的表和复杂的锁管理
|
|||
|
|
-- - 利用数据库原生的事务隔离和行锁机制
|
|||
|
|
-- - 自动处理锁超时和死锁情况
|
|||
|
|
|
|||
|
|
-- 如果未来需要在数据库层面加强约束,可以考虑:
|
|||
|
|
-- 1. 使用触发器在插入前检查
|
|||
|
|
-- 2. 使用 Exclusion Constraint (需要额外的辅助列)
|
|||
|
|
--
|
|||
|
|
-- 当前应用层实现已足够防止并发提现问题。
|