1

我的问题很简单,但答案可能很棘手。

我在 PHP 中,我想手动管理我的对象的唯一 ID。棘手的是管理原子性。我不希望 2 个元素获得相同的 ID。

“元素”在“组”中分组。在每个组中,我希望元素 ID 从 1 开始,并为该组中的每个插入增量增长。

我的第一个解决方案是在“组”表中有一个“lastID”列:

CREATE TABLE groups ( id INT AUTO_INCREMENT, lastId INT )
CREATE TABLE elements ( myId INT, multiple values ...)

为了避免许多元素具有相同的 ID,我必须更新 lastId 并在原子 SQL 查询中选择它。

之后,检索到一个,我有一个无法再次选择的唯一 ID,我可以插入我的元素。

我的问题是如何解决粗体部分?我的数据库是带有 MyISAM 引擎的 MySQL,所以没有事务支持。

UPDATE groups 
SET lastId = lastId + 1 
WHERE id = 42

SELECT lastId 
FROM groups
WHERE id = 42

有没有比这两个请求更原子的东西?

谢谢

4

3 回答 3

4
UPDATE groups SET lastId = last_insert_id(lastId + 1)

然后你可以得到你的新身份证

SELECT last_insert_id()

与参数一起使用last_insert_id将存储该值并在您稍后调用它时返回它。
这种生成自动编号的方法最适用于只有几行的 MyISAM 表(MyISAM 总是锁定整个表)。它还具有在事务期间不锁定表的好处(如果它是 InnoDB 表,则会发生这种情况)。

这是来自MySQL 手册

如果 expr 作为 LAST_INSERT_ID() 的参数给出,则参数的值由函数返回,并作为 LAST_INSERT_ID() 返回的下一个值被记住。这可以用来模拟序列:

创建一个表来保存序列计数器并对其进行初始化:

CREATE TABLE sequence (id INT NOT NULL); 
INSERT INTO sequence VALUES (0); 

使用该表生成序列号,如下所示:

UPDATE sequence SET id=LAST_INSERT_ID(id+1);
SELECT LAST_INSERT_ID(); 

UPDATE 语句递增序列计数器并导致对 LAST_INSERT_ID() 的下一次调用返回更新的值。SELECT 语句检索该值。mysql_insert_id() C API 函数也可用于获取值。请参阅第 21.8.3.37 节,“mysql_insert_id()”。

您可以在不调用 LAST_INSERT_ID() 的情况下生成序列,但是以这种方式使用该函数的效用是 ID 值在服务器中作为最后自动生成的值进行维护。它是多用户安全的,因为多个客户端可以发出 UPDATE 语句并使用 SELECT 语句(或 mysql_insert_id())获取自己的序列值,而不会影响生成自己的序列值的其他客户端或受其影响。

于 2012-07-24T21:03:05.750 回答
3

一种选择是让您使用漂亮的 MyISAM 功能,让每个组的 auto_increment 值递增。

CREATE UNIQUE INDEX elements_ix1 ON 元素(groupId,myID)

myID INT NOT NULL AUTO_INCREMENT

这比涉及更新单独表的任何事情都更加“原子”。请注意,这仅适用于 MyISAM,不适用于 InnoDB。


摘自http://dev.mysql.com/doc/refman/5.1/en/example-auto-increment.html

MyISAM 笔记

对于 MyISAM 表,您可以在多列索引中的辅助列上指定 AUTO_INCREMENT。在这种情况下,AUTO_INCREMENT 列的生成值计算为 MAX(auto_increment_column) + 1 WHERE prefix=given-prefix。当您要将数据放入有序组时,这很有用。

于 2012-07-24T21:09:13.447 回答
0

我假设您的 MySQL 安装也具有支持事务的 InnoDB 引擎。您只需要更改表的引擎类型。

于 2012-07-24T21:03:07.627 回答