在表格中,主要字段是名为ribiid
的Char(12)字段,其格式为RB##########
,
它需要自动增加它,为此我准备了以下代码:
function getid() {
global $connection;
$idquery = "SELECT ribiid FROM systems ORDER BY ribiid DESC LIMIT 1";
$idsave = mysqli_query($connection, $idquery);
$idresult = mysqli_fetch_assoc($idsave);
$idalpha = substr($idresult['ribiid'], 0, 2);
$idnumeric = substr($idresult, 2);
$newidnumeric = $idnumeric + 1;
$newid = $idalpha . $newidnumeric;
return $newid;
}
现在进行测试我在cmd中用id = RB0000000000
手动输入了一行,我使用php通过我的网页提交的下一个条目应该是RB0000000001
,但它正在RB1。
我该如何解决这个问题,这是我的第一个网络数据库。感谢
答案 0 :(得分:2)
您的问题是,在向$idnumeric
添加1时,PHP需要将其视为一个数字。数字中的前导零没有意义,所以它们被丢弃了。
要保留零,您可以使用sprintf
格式化生成的(递增的)数字:
$newid = sprintf("%s%010d", $idalpha, $newidnumeric);
此代码存在一个问题:它受竞争条件的影响。考虑如果脚本的两个实例并行运行会发生什么:
Instance A Instance B
T |
i | Reads ribiid RB..001 Reads ribiid RB..001
m | Generates next id RB..002 Generates next id RB..002
e v Writes RB..002 to DB
Writes RB..002 to DB => OOPS
如您所见,由于使用了重复的主键,这种情况将导致实例B无法插入记录。要解决这个问题,您需要消除竞争条件,您可以通过以下几种方式之一来完成竞争:
AUTO_INCREMENT
列,而不是手动插入值。虽然这意味着您不能再将“RB”前缀作为密钥的一部分,但可以将其移动到不同的列,并使PK成为这两列的组合。LOCK TABLES ribiid
(请注意,锁需要覆盖所有进程,而不仅仅是getid
函数)。锁定表是您通常想要避免的,但如果插入不频繁,则它是一种可用的实用解决方案。答案 1 :(得分:0)
您可以尝试这样的事情:
$newid = $idalpha . str_pad($newidnumeric, 10, '0', STR_PAD_LEFT);
这将添加零以达到十个字符。
答案 2 :(得分:0)
您可以使用以下函数再次填充数字字符串:
function pad_number($number, $pad=10){
$pad_zero = $pad - strlen($number.'');
$nstr = '';
for($i =0; $i< $pad_zero; $i++){
$nstr .="0";
}
$nstr .= $number;
return $nstr;
}
您可以在代码中使用此功能:
$newid = $idalpha . pad_number($newidnumeric);