PHP & MySQL: 如何创建唯一的“年-月-数”键?
PHP & MySQL: How to create unique `year-month-number` keys?
我必须为发票创建唯一 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 并且我有以下 table
本书
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;
returns 列号因为它是 auto increment column
和 LAST_INSERT_ID(number+1)
增加了最后插入的 number
(也可能是不同的用户?我不确定,我很难在文档中找到它 http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id)
此代码是否真的有效,或者如果人们同时执行此代码,它是否会创建多个相同的 ID?
编辑
假设当前month/year的个数为5。
为什么不可能 2 个人同时计算发票,以便两个查询同时将数字 5 升级为 6?在这种情况下,他们都会得到发票 ID“2017-11-6”吧?
类似这样的问题,您可以尝试一下——打开两个终端windows并使用mysql客户端。
mysql1> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 5 |
+------+-------+--------+
在两个并发会话中启动事务:
mysql1> begin;
mysql2> begin;
会话 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 |
+------+-------+--------+
会话 2 仍然看到原始数值,因为可重复读取事务隔离。但是一旦它尝试执行它自己的增量,它就会等待,因为会话 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
在会话 1 中提交:
mysql1> commit;
现在会话 2 中的 IODKU 完成,我们可以看到它第二次增加了数字:
mysql2> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 7 |
+------+-------+--------+
我必须为发票创建唯一 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 并且我有以下 table
本书
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;
returns 列号因为它是 auto increment column
和 LAST_INSERT_ID(number+1)
增加了最后插入的 number
(也可能是不同的用户?我不确定,我很难在文档中找到它 http://dev.mysql.com/doc/refman/5.7/en/information-functions.html#function_last-insert-id)
此代码是否真的有效,或者如果人们同时执行此代码,它是否会创建多个相同的 ID?
编辑 假设当前month/year的个数为5。 为什么不可能 2 个人同时计算发票,以便两个查询同时将数字 5 升级为 6?在这种情况下,他们都会得到发票 ID“2017-11-6”吧?
类似这样的问题,您可以尝试一下——打开两个终端windows并使用mysql客户端。
mysql1> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 5 |
+------+-------+--------+
在两个并发会话中启动事务:
mysql1> begin;
mysql2> begin;
会话 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 |
+------+-------+--------+
会话 2 仍然看到原始数值,因为可重复读取事务隔离。但是一旦它尝试执行它自己的增量,它就会等待,因为会话 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
在会话 1 中提交:
mysql1> commit;
现在会话 2 中的 IODKU 完成,我们可以看到它第二次增加了数字:
mysql2> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 | 5 | 7 |
+------+-------+--------+