Python操作MySQL如何同时执行select和update避免并发下发票号重复
问题解答
现有方案的可行性
你当前的实现逻辑本身已经可以避免并发场景下的发票号重复问题:
- MySQL的单条
UPDATE语句是原子操作,执行时会自动给对应行加行锁,同一时间只有一个请求能修改同一个email对应的last_invoice字段,所有并发请求的更新操作会串行执行,每个请求拿到的都是自增后的唯一值,不会出现两个请求拿到同一个last_invoice的情况。 - 你现有的先更新后查询的逻辑只要保证是针对同一个
email行操作,就不会产生重复发票号。
优化方案
你可以进一步简化逻辑,减少数据库交互次数:
方案1:使用UPDATE RETURNING语法(MySQL 8.0.20及以上版本支持)
直接通过一条语句完成更新和结果返回,全程原子性,效率更高:
UPDATE accounts SET last_invoice = last_invoice + 1 WHERE email = %s RETURNING CONCAT(invoice_prefix, last_invoice) AS invoice_no;
执行这条语句后直接就能拿到生成的发票号,不需要额外执行SELECT语句,也不需要单独在更新后提交事务再查询。
方案2:低版本MySQL兼容方案
如果你的MySQL版本不支持RETURNING语法,你原来的写法无需调整即可正常使用,只需要注意确保email字段是accounts表的唯一键,避免更新时匹配到多行即可。
额外兜底建议
你提到无法给发票号字段加UNIQUE约束的顾虑其实不存在:MySQL的唯一约束允许多个NULL值存在,只会对非NULL的值做唯一性校验,你完全可以给发票号字段加上唯一约束,作为逻辑之外的兜底保障,既不会影响允许NULL的业务场景,还能在逻辑出现异常时直接由数据库拦截重复数据,避免脏数据产生。
内容的提问来源于stack exchange,提问作者derikS4M1
相关产品推荐
相关产品推荐

