我遇到了竞争条件,因为我正在处理大量的并发问题。 我正在尝试将这两个mysql语句组合在一起同时执行。
我需要选择一行并更新同一行......
SELECT id_file FROM filenames WHERE pending=1 LIMIT 1;
UPDATE filenames SET pending=2 WHERE id_file=**id of select query**;
我遇到的竞争条件的另一个解决方案是执行UPDATE查询,其中pending = 1并以某种方式获取更新行的ID,但我不确定这是否可能?
由于
答案 0 :(得分:1)
您可以通过在表上只执行UPDATE
语句来避免“竞争”条件,允许它识别要修改的行,然后从行中检索列的值。
在您的情况下,有一个“技巧”返回列的值,刚刚更新的行中的id_file
列的值。您可以使用 LAST_INSERT_ID()
函数(仅当列为整数类型时)或MySQL 用户定义变量。
如果要检索的列的值是整数,则可以使用LAST_INSERT_ID()
函数(支持BIGINT-64值)。
例如:
UPDATE filenames
SET pending = 2
, id_file = LAST_INSERT_ID(id_file)
WHERE pending = 1
LIMIT 1;
成功执行UPDATE语句后,您需要验证至少有一行受到影响。 (如果任何行满足WHERE,并且语句成功,我们知道一行将受到影响。然后您可以在同一会话中检索该值:
SELECT LAST_INSERT_ID();
检索UPDATE语句处理的最后一行的id_file
列的值。请注意,如果UPDATE处理多行,则只有UPDATE处理的 last 行的值可用。 (但这对你来说不是问题,因为有一个LIMIT 1条款。)
同样,在依赖LAST_INSERT_ID()
函数返回的值之前,您需要确保实际更新了一行。
对于非整数列,您可以以类似的方式使用MySQL用户定义的变量,将列的值分配给用户定义的变量,然后立即检索存储在用户定义的变量中的值。
-- initialize user-defined variable, to "clear" any previous value
SELECT @id_file := NULL;
-- save value of id_file column into user-defined variable
UPDATE filenames
SET pending = 2
, id_file = (SELECT @id_file := id_file)
WHERE pending = 1
LIMIT 1;
-- retrieve value stored in user-defined variable
SELECT @id_file;
请注意,此变量的值在会话中保留。如果UPDATE语句没有找到满足谓词(WHERE子句)的任何行,则用户定义变量的值将不受影响...因此,为了确保您不会无意中获得“旧”值,您可能希望首先使用NULL初始化该变量。
请注意,后续触发的触发器不会修改该用户定义变量的值。 (用户定义的变量在当前会话中是“范围内”。)
也可以在触发器中对用户定义的变量进行赋值,但我不会证明这一点,并且我不建议你在触发器中进行。
答案 1 :(得分:1)
处理并发是transactions的基本功能之一。
将您的查询包装到一个事务中并告诉DBMS,您需要在FOR UPDATE
之间不要更改行:
BEGIN;
SELECT id_file FROM filenames WHERE pending=1 LIMIT 1 FOR UPDATE;
# do whatever you like
UPDATE filenames SET pending=2 WHERE id_file=**id of select query**;
COMMIT;
您可以通过4次mysqli_query
调用执行这些语句,并在其间执行任何操作,而无需担心数据库的一致性。选定的行将保存,直到您将其释放。