首页 > 解决方案 > 生成顺序唯一码,经常出现重复输入错误

问题描述

我目前正在使用 PHP 和 Laravel。

我想要做的是生成一个唯一且连续的字符串作为代码。
在此示例中,代码用于采购订单。

我想要的是这样的:

PO/000001
PO/000002
PO/000003
PO/000004
PO/000005
PO/000006

数据库表模式:

create table `purchase_orders` (
`id` int unsigned not null auto_increment primary key,
`code` varchar(191) not null, 
...
...
)

alter table `purchase_orders` add unique `purchase_orders_code_unique`(`code`)

这看起来很简单,我只需要获取auto_incrementID,所以code对应的id,或多或少是这样的:

id | code
 1 | PO/000001
 2 | PO/000002
 3 | PO/000003
 4 | PO/000004
 5 | PO/000005
 6 | PO/000006

我使用的代码:(使用 Laravel 的 ORM 语法)

$count = PurchaseOrders::max('id'); // Equivalent to select MAX (`id`) from purchase_orders
$code = 'PO/' . sprintf('%08d', $count + 1);

理论上它工作得很好,但实际上,经常发生“碰撞”,其中id不等于code它产生的,有时code大于/领先于id. 例如,它经常这样发生:

 id | code
... | ...
199 | PO/000199
200 | PO/000200
201 | PO/000202

下一笔交易将有idof 202,并且生成code的应该是PO/000202。它将触发完整性约束违规错误,因为PO/000202已在id: 201.

我大量使用数据库事务和提交,有时创建采购订单需要一些时间,而且还有多个用户正在创建采购订单。我不知道它到底是怎么发生的,但冲突经常发生,大约 100 笔交易左右。


这是一个现场项目中的一个事件: id是204,code是205

如您所见,code大于id。下一个要插入的代码是...000205,我的客户报错:

SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry   
'PRCV/JKT/G/2019/00000205' for key 'dlvr_payments_code_unique'

您还可以看到idandcode根本不相等


我之前也尝试过其他代码生成方法,而不是MAX('id')使用COUNT(*),但似乎比MAX('id').

所以,问题是,我做错了什么?我怎样才能让它确保每次都有一个唯一的代码,这样以后就不会再发生这种情况了?

我一直在考虑使用 Redis 或者一些键值数据库来存储计数,有必要吗?

标签: phpmysqllaravelunique-constraint

解决方案


不要这样做!

不要依赖PK来获得序号。它让你在不同的街道上。

我建议将您最后插入的采购订单ID 存储在单独的表中,并相应地更新它。

除了维护表之外,将其存储在缓存(即redis)中可以提高应用程序的性能。

希望能帮助到你!


推荐阅读