PHP&;MySQL:如何创建唯一的“年-月数”键?

PHP&;MySQL:如何创建唯一的“年-月数”键?,php,mysql,innodb,auto-increment,Php,Mysql,Innodb,Auto Increment,我必须为发票创建唯一的id。每个发票id的格式为年-月编号,由发票的当前年份和月份以及从1开始的递增编号组成(不允许有间隙) 例如,如果我们在2017年1月有4张发票,我将有以下4张发票id: 2017-1-1 2017-1-2 2017-1-3 2017-1-4 现在我想创建一个应用程序来创建这些唯一的id。特别是,我想确保即使两个人同时请求一个发票号码,他们也应该得到不同的id 我正在使用InnoDB,我有下表 书籍 year | month | number | ---------

我必须为发票创建唯一的id。每个发票id的格式为
年-月编号
,由发票的当前年份和月份以及从1开始的递增编号组成(不允许有间隙)

例如,如果我们在2017年1月有4张发票,我将有以下4张发票id:

2017-1-1
2017-1-2
2017-1-3
2017-1-4
现在我想创建一个应用程序来创建这些唯一的id。特别是,我想确保即使两个人同时请求一个发票号码,他们也应该得到不同的id

我正在使用InnoDB,我有下表

书籍

year  | month  | number | 
------------------------
2017  | 7      | 2      | 
2017  | 6      | 5      |
2017  | 5      | 6      |
如果未为
年-月
对创建发票,则数据库中没有条目。主键是
年-月
对,
数字
是一个
自动递增索引

假设我计算下一个发票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\u id
返回列号,因为它是一个
自动递增列
最后插入的ID(数字+1)
增加了最后插入的
(也可能是由其他用户插入的?我不确定,在文档中查找时遇到问题)

这段代码真的有效吗?或者如果人们同时执行这段代码,它可能会创建多个相同的id吗

编辑 假设当前月/年的数量为5。
为什么两个人不可能同时计算一张发票,以便两个查询同时将数字5升级到6?在这种情况下,他们都会得到发票id“2017-11-6”,对吗

对于这样的问题,您可以打开两个终端窗口并使用mysql客户端来尝试

mysql1> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 |     5 |      5 |
+------+-------+--------+
在两个并发会话中启动事务:

mysql1> begin;

mysql2> begin;
会话1执行IODKU并增加数字(但尚未提交,因为
begin
隐式地将我们带出自动提交模式):

由于可重复读取事务隔离,会话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 |
+------+-------+--------+

你没有AI专栏吗?如果没有,您应该这样做,因为这将自动使所有记录都唯一。@Fred ii-
number
字段是一个
AI
列,但我会随着更新而增加它。您不必为它增加AI,它会自行增加。我觉得我没有完全理解你想在这里做什么。你能在查询中添加
mysqli\u error($db)
并查看返回的结果吗?@Fred ii-你是对的,这是使用
AI
字段的一种非常不寻常的方式。但是字段
number
只是一个
AI
键,因此它由
$db->insert\u id返回。事实上,它甚至不是独一无二的。可以同时在数据库中显示
2017-7-2
2017-8-2
。但是
2017-7-2
2017-7-3
是不可能的。我在这里发现了这个技巧(),但我不确定它是否会给两个不同的用户提供相同的发票id。嗯……-
001
等是否与
number
列相关?
和数字是一个自动递增索引
不会以前导零递增,因此您可能需要找到另一种方法(我以前在某个地方见过这种方法),并为其添加另一列,
id
作为AI,并删除/更改当前的AI列。也许我没有收到你的问题/相关列和
00X\u integer
,所以我可能无法在这方面提供更多帮助,对不起,亚当。希望我能在这方面多帮点忙。看看其他人是否能提供(另一)帮助。注意,这样您就不会在第一次插入时设置
最后一次插入\u ID
。为了解决这一问题,应该将其
插入账面价值(2017年5月,最后一次插入id(1))…
谢谢,这也是对您2016年7月最后一次回答的一个很好的补充:P。我想我需要更深入地了解为什么
$stmt=$db->prepare$stmt->execute
mysql1>begin;相同。。。mysql1>提交。但可以肯定的是,如果没有innodb,这是行不通的,对吗事实上,现在我可以测试它了:D.@Adam与
mysqli
的交易,你应该使用and.@PaulSpiegel-tahnk!你也知道一些基本的文献,涵盖了这类东西,并且比文献更容易阅读吗?@Adam,我不是从一本书中学到这一点的。首先我获得了计算机科学学位。然后我读了很多文档。然后我用逻辑来做实验来检验我的理解。20年来,我一直在互联网上回答像你这样的问题。这需要时间,但没有比这更好的学习方法了。
mysql2> select * from book;
+------+-------+--------+
| year | month | number |
+------+-------+--------+
| 2017 |     5 |      7 |
+------+-------+--------+