我正在使用PHP / MySQL,在打开输入屏幕时为每个条目生成计数器代码。
以下是我正在使用的代码
$qresult = $db->query("SELECT count(*) FROM ap_aurora_projects");
$row = $qresult->fetch_row();
$slno = $row[0] + 1;
$today = date("ymd");
$code = $today . "-" . $slno;
此代码正确生成并在创建记录之前向用户显示。问题是当多个用户同时打开代码在屏幕上重复时。
避免重复的方法是什么。
我尝试创建一个单独的表来存储最新的数字并为每个请求递增,但问题是,如果用户取消该条目,则该数字将丢失。
修改
当一个用户生成代码并插入记录时,代码正常工作。但问题是如果多个用户同时打开,它会在屏幕上为它们生成相同的号码。如果所有人都试图保存记录,那么它就会重复。 请注意,我生成此号码并在输入屏幕中显示最初不是在保存记录时。
答案 0 :(得分:7)
我认为您在问题中显示的代码已经过简化,您不能按照另一个答案的建议使用AUTO_INCREMENT列。
您需要锁定表格以供阅读,直到更新为止。按以下顺序执行MySQL查询:
LOCK TABLES ap_aurora_projects READ;
SELECT count(*) FROM ap_aurora_projects WHERE ...;
//Update here ...
UNLOCK TABLES;
有关锁定整个表的更多信息,请访问: http://dev.mysql.com/doc/refman/5.6/en/lock-tables.html
如果您使用的是InnoDB存储引擎,可以在此处阅读有关高级(行)锁定和事务的更多信息: http://dev.mysql.com/doc/refman/5.6/en/innodb-transaction-model.html
答案 1 :(得分:6)
以下是您需要做的事情:
首先,创建一个表:
create table uniqueId ( id bigint(20) unsigned not null auto_increment primary key );
其次,使用此代码(我不知道您使用哪个MySQL代码,因此我将使用常用的代码):
$link = mysql_connect('localhost', 'user', 'password');
if (!$link) {
die('Could not connect: ' . mysql_error());
}
mysql_select_db('mydb');
mysql_query("INSERT IGNORE INTO uniqueId VALUES (NULL);");
printf("Last inserted record has id %f\n", date("ymd") . "-" . mysql_insert_id());
通过插入而不是选择,您确定不会有重复。
答案 2 :(得分:4)
如您所发现的那样,创建自己的自动增量标识符很困难且容易出错。您应该考虑使用MySQL AUTO_INCREMENT feature和相应的LAST_INSERT_ID()
函数,该函数将返回该会话中最近插入的记录的ID 。
该链接的主要摘录:
这些函数是特定于连接的,因此它们的返回值是 不受另一个同时执行插入的连接的影响。
但是你必须改变你的方法。您不必在创建记录之前在屏幕上显示ID,而是需要等到记录的插入。或者,如果您真的需要显示此ID,则插入空白记录以创建并返回ID,然后从用户输入的数据中编辑该记录,而不是执行插入。
一个令人担忧的想法是,您需要向系统用户显示内部主键。密钥不是自然的(如政府颁发的标识符),它由系统生成。这闻起来有点糟糕的设计。通常,主键值永远不会显示给用户,并且会使用其他一些代理标识符。