我目前正在使用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,因此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
下一个事务将具有id
中的202
,并且生成的code
应该是PO/000202
。由于PO/000202
上已经使用了id: 201
,因此它将触发违反完整性约束错误。
我使用数据库事务并投入大量资金,有时创建采购订单会花费一些时间,并且还有多个用户正在创建采购订单。我不知道它是如何发生的,但是冲突经常发生,大约100笔左右的交易。
如您所见,code
比id
大。下一个要插入的代码为...000205
,我的客户报告了一个错误:
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry
'PRCV/JKT/G/2019/00000205' for key 'dlvr_payments_code_unique'
您还可以看到id
和code
根本不相等
我之前也尝试过其他代码生成方法,而不是使用MAX('id')
来代替COUNT(*)
,但似乎比MAX('id')
还要糟糕。
所以,问题是,我做错了什么?我该如何确保每次都有唯一的代码,以免将来再次发生?
我一直在考虑使用Redis或一些键值数据库来存储计数,这是必要的吗?
答案 0 :(得分:2)
不要这样做!
不要依赖 PK 来获得连续编号。它使您流连于各种街道。
我建议将您最后插入的购买订单 ID存储在单独的表格中,并保持相应更新。
在维护表的同时,将其存储在缓存(即redis)中可以提高应用程序的性能。
希望有帮助!