我有一个生成唯一事务ID的php应用程序。但是,我发现有时,两个事务具有相同的ID。 下面是我的代码。如果我能在给定两个交易相同的传输时知道原因,我将不胜感激。另外,我希望在新的一年开始时从 1 开始计数。我不知道该怎么做。
对于问题 1:
<?php
$db = mysqli_query($connection,"SELECT * FROM tab_requisition");
$nrw = mysqli_num_rows($db);
$refID= ("NR".date("Y").($nrw+1));?>
<tr>
<th>Requisition ID:</th>
<td><input type="text" name="refid" value="<?php echo $refID;?>" size="100" readonly="readonly"/></td></tr>
对于问题 2:我怎样才能使上述$refID在每年年初从 1 开始计数。像NR20161,NR20162.....NR20165000。假设在 2016 年 12 月 31 日结束时,最后一个 id 是 NR20165000。我希望下一个从NR20171开始NR20172,......NR2017XXXXX
我将不胜感激任何关于如何防止上述重复并在每年年初重置的回复。
$nrw = mysqli_num_rows($db);
$refID= ("NR".date("Y").($nrw+1));?>
这是绝对的不。如果有一天删除行怎么办?您的下一个ID将下降,但它已经存在,这就是您收到该错误的原因。
不能使用行计数来有效地决定下一个数字应该是什么。
您可以简单地为此使用自动递增值,您的RDBMS将处理冲突。然后,您可以使用该自动递增值生成字母数字唯一 ID。
为此,使用以下列创建您自己的表"数字组":
- 年份:整数
- 下一个数字: 整数
与主键在年。
如果随后想要获取一年的下一个数字,请使用以下 SQL 查询:
insert into NumberGroups(Year, NextNumber) values (2016, LAST_INSERT_ID(1) + 1) on duplicate key update NextNumber = LAST_INSERT_ID(NextNumber) + 1;
select LAST_INSERT_ID();
在一次调用中执行此操作,mysqli_query()
将 2016 替换为您想要计数器的年份。然后,这将返回要使用的下一个免费号码,从每年的 1 开始。
它的作用:
它检查表中是否已有给定年份的行。如果给定年份没有行,则会插入一个值为 2 的新行作为 NextNumber,并将 LAST_INSERT_ID() 设置为 1。如果给定年份已经有一行,则更新现有行,并将该行的 NextNumber 增加 1,同时记住 LAST_INSERT_ID() 中 NextNumber 的旧值。最后,我们在 LAST_INSERT_ID() 中设置的值返回给调用方。
当前方法中的问题是,当多个操作并行运行时,两个操作可以读取表中的相同行计数。如果需要唯一的计数器,则必须确保并行运行的两个活动不会读取相同的值。您可以通过使用具有正确隔离级别的事务来执行此操作,也可以通过读取当前值并将其递增到同一个 SQL 语句中来执行此操作(如在此变体中)。
资源:
- 在重复密钥更新时插入
- LAST_INSERT_ID()
补充一下Hanky Panky的答案。
注意:以下代码未测试
将year
列添加到数据库表(以及自动递增的唯一 ID),
当交易实际发生时:
INSERT INTO `tab_requisition` (year, ...) VALUES(YEAR(NOW()), ...)
捕获交易/记录的真实唯一ID
$ID = mysqli_insert_id ($db);
获取当前年度记录计数:
SELECT COUNT(*) FROM `tab_requisition` WHERE `year` = YEAR(NOW())
-- below line should take care of raise condition (if another record was added meanwhile)
AND `id` <= '.$ID
生成您的序列号/参考编号
$prefix = 'NR';
$year = date('Y');
$count = str_pad($year_record_count,6,'0', STR_PAD_LEFT);
$refNum = $year . $count;
最后,用您的refNum
更新您的记录:
UPDATE `tab_requisition` SET `ref_num` = "'.$refNum.'" WHERE id = '.$ID
str_pad
用于将计数填充到特定长度,这将为排序等生成正确的编号。
而不是
NR20171
NR20172
NR201712
NR2017137
它会变成
NR2017000001
NR2017000002
NR2017000012
NR2017000137
我知道,这需要多次数据库调用,但它可能为您工作,具体取决于服务器负载/流量