Magento 2 创建订单时偶发 Duplicate entry,或后台看到不同订单使用相同的显示订单号,很多人会直接修改 sequence_order_* 表的 AUTO_INCREMENT。这样可能暂时绕过一条错误,却让订单、发票、发货和退款编号继续错位。先分清实体主键与业务 increment_id,再处理 Sequence。
entity_id 与 increment_id 不是同一个编号
sales_order.entity_id 是数据库实体主键;increment_id 是客户和管理员看到的订单号。Magento 会根据 store 对应的 sales sequence profile 生成 increment_id,前缀、后缀、步长和起始值都可能参与计算。
SELECT entity_id, increment_id, store_id, created_at
FROM sales_order
ORDER BY entity_id DESC
LIMIT 20;
如果 entity_id 正常递增而 increment_id 冲突,问题在业务编号生成或迁移;如果主键也异常,则要调查数据库复制、导入或人工写表。
确认 Store 与 Sequence 元数据映射
查看 sequence 相关元数据和 profile,找到当前 store 的实体类型与实际 sequence 表。不同安装的表后缀可能与 store ID 对应,但不要仅凭表名猜测关系。多商店克隆、删除后重建 Store、数据库合并时,最容易留下错误映射。
检查实际订单号是否在两个 store 之间重复。业务上如果允许各店独立编号,显示相同数字未必违反数据库唯一索引;但 ERP 或支付系统若把 increment_id 当作全局唯一键,就必须在集成层加入 store 维度或配置不同前缀。
不要在有并发写入时手工重置 AUTO_INCREMENT
直接把 sequence 表的 AUTO_INCREMENT 改小,下一笔编号可能与历史订单冲突。改大虽然通常不重复,但会产生跳号,也可能与 profile 的 start_value、step 计算不一致。任何调整前都要查历史最大编号、当前 sequence 值、商店前缀和外部系统已使用范围。
数据迁移时不要把旧站订单导入后又让新站从默认 1 开始。迁移脚本应在停止写入的窗口完成,建立明确的新编号起点,并验证所有销售实体。
自定义订单号模块要保证原子性
使用“查询最大值再加一”的代码在并发下必然有竞争:两个请求可能读到同一个最大值。正确实现应依赖数据库原子自增或锁定的 sequence 服务,并在事务和失败重试中保持唯一。
模块如果只改订单号,没有同步发票、Shipment、Credit Memo 或支付 merchant reference,也会造成运营混乱。检查它是否通过公开扩展点实现,而不是 around plugin 完全替换核心 sequence 逻辑。
修复后并发创建多笔测试订单,覆盖至少两个 Store View 和两种支付方式,确认数据库无重复、编号前缀符合规则、支付与 ERP 收到的引用唯一。编号允许跳跃,但不应倒退、复用或因失败订单而强行补齐。

