-- 迁移脚本:为 activity_draw_logs 表添加唯一索引,防止重复开奖 -- 创建时间:2025-12-18 -- 问题描述:定时抽奖时可能因为竞态条件导致一个订单发放多个奖品 -- 解决方案: -- 1. 代码层面:先创建开奖日志,成功后再发放奖励(已完成) -- 2. 数据库层面:添加唯一索引作为最后一道防线 -- 步骤1:检查是否存在重复数据 SELECT order_id, COUNT(*) as cnt FROM activity_draw_logs GROUP BY order_id, issue_id HAVING cnt > 1; -- 步骤2:如果有重复数据,先清理重复数据(保留最早的一条) -- 注意:执行前请先备份数据 -- DELETE a FROM activity_draw_logs a -- INNER JOIN ( -- SELECT order_id, issue_id, MIN(id) as min_id -- FROM activity_draw_logs -- GROUP BY order_id, issue_id -- HAVING COUNT(*) > 1 -- ) b ON a.order_id = b.order_id AND a.issue_id = b.issue_id AND a.id != b.min_id; -- 步骤3:添加唯一索引(order_id + issue_id + reward_id 组合唯一) -- 注意:对于一番赏,一个订单可能有多个格位,所以不能仅用 order_id 作为唯一键 -- 对于默认玩法,一个订单也可能有多次抽奖(count > 1) -- 因此这里添加的是复合唯一索引:order_id + reward_id + created_at(精确到秒) -- 或者使用 order_id + 序号 的方式 -- 方案A:对于一番赏,每个订单的每个格位只发一次奖 -- 方案B:根据业务逻辑,可以考虑在代码层添加 slot_index 信息 -- 推荐方案:为确保安全,暂不添加唯一索引,因为: -- 1. 代码已修复为"先记录日志,再发奖"的模式 -- 2. 不同的玩法(一番赏、默认玩法)有不同的唯一性约束需求 -- 3. 添加索引可能导致历史数据迁移问题 -- 如果确认需要添加索引,可以执行: -- ALTER TABLE activity_draw_logs ADD INDEX idx_order_issue (order_id, issue_id); -- 或者添加更严格的唯一索引(需要先清理重复数据): -- ALTER TABLE activity_draw_logs ADD UNIQUE INDEX uk_order_issue_reward (order_id, issue_id, reward_id);