同时选择并插入

时间:2012-01-19 17:44:45

标签: mysql sql

所以,我需要获得名为chat_id的最大字段数,之后我需要将其递增1并在该字段中插入一些数据,因此查询应该如下所示:

SELECT MAX(`chat_id`) FROM `messages`;

让我们说现在我需要插入新数据

INSERT INTO `messages` SET `chat id` = 11 -- other data here....

所以它会以我想要的方式工作,但我的问题是,如果在那个时候我正在增加并插入新记录,其他用户会做同样的事情?比已经有11 id的记录,它可能会弄乱我的数据有没有办法确保正确的ID到我需要的地方,顺便说一下,我不能用户自动增加。

编辑,因为我说我不能使用自动增量因为该表已经有自动增量的id字段,这个id适用于不同的porpuse,也不是唯一的它不可能是唯一的

编辑2 通过重做整个表格结构来解决这个问题,因为没有人给我更好的想法

4 个答案:

答案 0 :(得分:5)

请勿尝试自行完成此操作。你已经发现了这种方法的一个缺陷。我不确定你为什么说你不能在这里使用auto increment。这真的是要走的路。

CREATE TABLE messages (
    chat_id INT NOT NULL AUTO_INCREMENT,
    ....
)

答案 1 :(得分:3)

如果您不能使用自动增量主键,那么您将不得不专门锁定表(这通常不是一个好主意),或者准备好遇到失败。

假设chat_id列是UNIQUE(它应该来自您所说的),您可以将这两个查询放在循环中。如果INSERT成功,那么一切都很好,你可以突破循环并继续。否则,这意味着其他人设法从你手中抢夺了这个特定的id,所以重复这个过程直到成功。

此时我必须提到你不应该在生产代码中实际使用一种完全天真的方法(例如,你可能希望在放弃之前设置多少次迭代的上限)并且 this如果对数据库存在很多争用,那么解决方案将无法正常工作(它可以正常工作以确保偶尔的竞争不会导致您出现问题)。在决定之前,您应该检查您的访问模式和负载。

答案 2 :(得分:1)

AUTO_INCREMENT可以解决这个问题。但对于其他类似情况,这将是transactions的一个很好的用途。如果您使用的是InnoDb引擎,则可以使用事务来确保按特定顺序执行操作,以确保数据保持一致。

答案 3 :(得分:0)

您可以通过使用MySQL内置的uuid()函数来计算新的主键值,而不是将其留给自动递增功能来解决此问题。

更改表以将messages.chat_id设为char(36)并删除AUTO_INCREMENT子句。

然后执行以下操作:

# Generate a unique primary key value before inserting.
declare new_id char(36);
select uuid() into new_id;

# Insert the new record.
insert into messages
(chat_id, ...)
values
(new_id, ...);

# Select the new record.
select *
from messages
where chat_id = new_id;

uuid()上的MySQL's documentation说:

  

UUID被设计为在时空上全球唯一的数字。即使两次调用UUID()会在两个未连接的独立设备上执行,也会产生两个不同的值。

这意味着将uuid生成的值用作主键值是绝对安全的。

这样,您可以预测新记录的主键值将是 ,然后再插入它,然后通过它进行查询,以确保没有其他进程在插入和选择之间从您那里“窃取”该ID。从而消除了交易的需要。