生成顺序唯一码,经常出现重复录入错误
Generating sequential unique code, often times occurs duplicate entry error
我目前正在使用 PHP & Laravel。
我想做的是生成一个唯一的顺序字符串作为代码。
在此示例中,代码用于采购订单。
我想要的是这样的:
PO/000001
PO/000002
PO/000003
PO/000004
PO/000005
PO/000006
数据库table架构:
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);
理论上它很好用,但实际上,经常会发生 'collision',其中 id
不等于它生成的 code
,有时 code
比 id
bigger/ahead。比如经常会这样:
id | code
... | ...
199 | PO/000199
200 | PO/000200
201 | PO/000202
下一笔交易将具有 202
的 id
,生成的 code
应该是 PO/000202
。它将触发 Integrity constraint violation 错误,因为 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')
代替MAX('id')
,但是好像比MAX('id')
.
差
那么,问题来了,我做错了什么?我怎样才能让它每次都确保唯一的代码,这样以后就不会再发生这种情况了?
我一直在考虑使用 Redis 或一些键值数据库来存储计数,是否有必要?
不要这样做!
不要依赖PK来实现序号。它让你在不同的尽头街道。
我建议将您最后插入的 采购订单 ID 存储在单独的 table 中,并相应地不断更新它。
在维护 table 的同时,将其存储在缓存(即 Redis)中可以提高应用程序的性能。
希望对您有所帮助!
我目前正在使用 PHP & Laravel。
我想做的是生成一个唯一的顺序字符串作为代码。
在此示例中,代码用于采购订单。
我想要的是这样的:
PO/000001
PO/000002
PO/000003
PO/000004
PO/000005
PO/000006
数据库table架构:
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);
理论上它很好用,但实际上,经常会发生 'collision',其中 id
不等于它生成的 code
,有时 code
比 id
bigger/ahead。比如经常会这样:
id | code
... | ...
199 | PO/000199
200 | PO/000200
201 | PO/000202
下一笔交易将具有 202
的 id
,生成的 code
应该是 PO/000202
。它将触发 Integrity constraint violation 错误,因为 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')
代替MAX('id')
,但是好像比MAX('id')
.
那么,问题来了,我做错了什么?我怎样才能让它每次都确保唯一的代码,这样以后就不会再发生这种情况了?
我一直在考虑使用 Redis 或一些键值数据库来存储计数,是否有必要?
不要这样做!
不要依赖PK来实现序号。它让你在不同的尽头街道。
我建议将您最后插入的 采购订单 ID 存储在单独的 table 中,并相应地不断更新它。
在维护 table 的同时,将其存储在缓存(即 Redis)中可以提高应用程序的性能。
希望对您有所帮助!