You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

MySQL如何避免POS应用并发提交时增量发票号重复录入问题

发票号并发重复问题的SQL锁解决方案

核心问题本质

你遇到的重复问题根源是「读取最后发票号→加1→插入新发票」三个操作是非原子操作,高并发下多个请求会读到相同的最后发票号,最终生成重复编号。

可以用SQL锁解决,推荐悲观锁方案(适配你的场景实现成本最低)

共享主机环境一般使用MySQL数据库,直接用自带的排他锁即可实现操作原子化,步骤如下:

  • 先给发票号字段添加唯一索引,作为兜底安全规则,避免任何极端情况下出现重复发票号的脏数据
  • 生成发票号的整个逻辑包裹在数据库事务中,查询最后发票号时加排他锁,保证同一时间只有一个请求能读取到最新编号,其他请求会阻塞等待当前操作完成

CodeIgniter 实现参考代码

// 开启CodeIgniter事务,会自动处理异常回滚
$this->db->trans_start();

// 加排他锁查询最新发票号,FOR UPDATE会锁定查询范围,其他事务需等待当前事务结束后才能读取
$query = $this->db->query("SELECT MAX(invoice_no) as last_no FROM 你的发票表名 FOR UPDATE");
$lastNo = $query->row()->last_no ?? 0; // 如果是第一张发票默认从1开始
$newInvoiceNo = $lastNo + 1;

// 拼接所有表单提交的销售数据,插入发票记录
$insertData = [
    'invoice_no' => $newInvoiceNo,
    // 其余你需要保存的表单字段,比如客户信息、金额、商品明细等
];
$this->db->insert('你的发票表名', $insertData);

// 提交事务,释放锁
$this->db->trans_complete();

// 事务失败兜底逻辑,自动重试无需暴露给用户
if ($this->db->trans_status() === false) {
    // 冲突概率极低,这里可以自动重试1~2次,用户完全无感知,不会丢失表单数据
}

额外优化建议

如果你的业务允许发票号不要求完全连续(比如偶尔出现跳号不影响财务规则),可以直接将发票号字段设置为数据库自增主键,数据库会自动处理并发递增逻辑,不需要手动编写锁相关代码,是成本最低的解决方案。


内容的提问来源于stack exchange,提问作者Chinmoy

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.06 14:30:01