我必须为发票创建唯一 ID。每个发票 ID 的格式都是 year-month-number
,它由发票的当前年份和月份以及一个从 1 开始的递增数字组成(不允许有间隙)。
例如,如果我们在 2017 年 1 月有 4 张发票,我将有以下 4 个发票 ID:
2017-1-1
2017-1-2
2017-1-3
2017-1-4
现在我想创建一个应用来创建这些唯一 ID。特别是我想确保即使 2 个人同时请求发票编号,他们也应该获得不同的 ID。
我正在使用 InnoDB 并且我有下表
书
year | month | number |
------------------------
2017 | 7 | 2 |
2017 | 6 | 5 |
2017 | 5 | 6 |
如果尚未为 year-month
对创建发票,则数据库中没有条目。主键是 year-month
对,number
是 auto increment index
。
假设我会这样计算下一个发票 ID:
$stmt = $db->prepare('INSERT INTO book(year,month,number)
VALUES (?,?,1)
ON DUPLICATE KEY UPDATE number= LAST_INSERT_ID(number+1)');
$stmt->bind_param('ii', $year, $month);
$stmt->execute();
echo 'Next invoice id: ' . $year . '-' . $month . - . $db->insert_id;
说明:$db->insert_id;
返回列号,因为它是一个自动递增列
并且LAST_INSERT_ID(number+1)
递增最后插入的 number
(也可能是由不同的用户插入的?我不确定,我很难在文档 http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id 中找到它)
这段代码真的有效吗,或者如果人们同时执行这段代码,它是否会创建多个相同的 ID?
编辑 假设当前月/年的数量为 5。 为什么不可能 2 个人同时计算发票,以便两个查询同时将数字 5 升级为 6?在这种情况下,他们都会得到发票 ID“2017-11-6”吧?
最佳答案
对于这样的问题,您可以尝试一下——打开两个终端窗口并使用 mysql 客户端。
mysql1> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 5 |
+------+-------+--------+
在两个并发 session 中启动事务:
mysql1> begin;
mysql2> begin;
session 1 执行 IODKU 并递增数字(但尚未提交,因为 begin
隐式地使我们退出自动提交模式):
mysql11> insert into book values (2017, 5, 0)
on duplicate key update number = last_insert_id(number+1);
mysql1> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 6 |
+------+-------+--------+
session 2 仍然看到原始数值,因为可重复读取事务隔离。但是一旦它尝试执行它自己的增量,它就会等待,因为 session 1 仍然锁定该行。
mysql2> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 5 |
+------+-------+--------+
mysql12> insert into book values (2017, 5, 0)
on duplicate key update number = last_insert_id(number+1);
-- waits for lock
在 session 1 中提交:
mysql1> commit;
现在 session 2 中的 IODKU 完成了,我们可以看到它第二次增加了数字:
mysql2> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 7 |
+------+-------+--------+
关于PHP & MySQL : How to create unique `year-month-number` keys?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47460729/