我有一个php应用程序,它生成一个唯一的事务ID。但是,我发现有时两个事务具有相同的ID。以下是我的代码。如果我能够知道两个交易同一个transid的原因,我将不胜感激。另外,我希望transid从新年开始时的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。我希望下一个ID开始于NR20171,NR20172,...... NR2017XXXXX
对于如何防止上述复制并在每年年初重置时,我将不胜感激。
答案 0 :(得分:2)
$nrw = mysqli_num_rows($db);
$refID= ("NR".date("Y").($nrw+1));?>
那是绝对的否。如果你有一天删除行怎么办?您的下一个ID将会关闭,但它已经存在,这就是您收到该错误的原因。
您无法使用行计数来有效地确定下一个数字应该是什么。
您可以简单地使用自动增量值,您的RDBMS将处理冲突。然后,您可以使用该自动增量值生成字母数字唯一ID。
答案 1 :(得分:1)
创建自己的表&#34; NumberGroups&#34;为此目的,使用以下列:
年初主键。
如果您希望获得一年的下一个数字,请使用以下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语句中将其递增来执行此操作(如此变体中所示)。
资源:
答案 2 :(得分:1)
加入Hanky Panky的回答。
注意:以下代码未经过测试
将year
列添加到数据库表(与自动递增唯一ID一起),
当交易实际发生时:
INSERT INTO `tab_requisition` (year, ...) VALUES(YEAR(NOW()), ...)
为事务/记录捕获REAL唯一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
我知道,它需要几次数据库调用,但它可能适合您,具体取决于服务器负载/流量