生成顺序唯一代码,通常会发生重复输入错误

时间:2019-07-16 12:17:27

标签: php mysql laravel unique-constraint

我目前正在使用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_increment ID,因此codeid相对应,如下所示:

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

下一个事务将具有id中的202,并且生成的code应该是PO/000202。由于PO/000202上已经使用了id: 201,因此它将触发违反完整性约束错误。

我使用数据库事务并投入大量资金,有时创建采购订单会花费一些时间,并且还有多个用户正在创建采购订单。我不知道它是如何发生的,但是冲突经常发生,大约100笔左右的交易。


这是一个正在进行的项目中的一个事件: id is 204, code is 205

如您所见,codeid大。下一个要插入的代码为...000205,我的客户报告了一个错误:

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

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


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

所以,问题是,我做错了什么?我该如何确保每次都有唯一的代码,以免将来再次发生?

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

1 个答案:

答案 0 :(得分:2)

不要这样做!

不要依赖 PK 来获得连续编号。它使您流连于各种街道。

我建议将您最后插入的购买订单 ID存储在单独的表格中,并保持相应更新。

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

希望有帮助!