我遇到了问题,无法选择正确的解决方案。
我有一个 SELECT 查询,用于从表中选择记录。 这些记录的状态列如下所示。
<display-name>myApp</display-name>
<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>
现在,在 SELECT 之后,我必须更新状态列。 我怎样才能避免竞争条件?
我想要实现的是,一旦某人(会话)选择了某些内容,在我不手动释放它之前,其他任何人都无法选择此内容(例如使用状态列)。
思想?
答案 0 :(得分:2)
There是一些mysql文档,thar可能对解决你的任务很有意思,不确定它是否适合你的需要,但是它描述了做select然后更新的正确方法。
所描述的技术不会阻止其他会话读取,但会阻止写入所选记录直到事务结束。
它包含一个类似于您的问题的示例:
SELECT counter_field FROM child_codes FOR UPDATE;
UPDATE child_codes SET counter_field = counter_field + 1;
您需要使用Innodb引擎,并且您的程序使用事务。
如果您只需要短时间锁定,即一个会话选择带锁的行,更新它并在一个会话中释放锁定,那么您根本不需要字段状态,只需使用select ... for update
和{{ 1}}所以如果所有会话都将这两个会话与事务select ... lock in share mode
结合使用,然后select... for update
进行修改,update
只需阅读 - 这将解决您的要求。
如果您需要长时间锁定,请在一个会话中选择并锁定,然后在另一个会话中进行更新和释放,然后使用一些存储来保持锁定状态,并且所有会话都应按照以下说明使用:select ... with shared lock
并在一个会话中设置状态和状态所有者,然后在另一个会话中select ... for update
检查状态和所有者,更新和删除状态 - 用于更新方案,以及读取方案:select for update
检查状态。
答案 1 :(得分:1)
你可以做一些准备工作。在表格中添加一列sessionId
。它必须是NULL
- 能够并且它将包含获取行的会话的唯一ID。还要在此新列上添加索引;我们将使用该列搜索表格中的行。
ALTER TABLE `tbl`
ADD COLUMN `sessionId` CHAR(32) DEFAULT NULL,
ADD INDEX `sessionId`(`sessionId`)
当会话需要获取某些行(基于某些条件)时,运行:
UPDATE `tbl`
SET `sessionId` = 'aaa'
WHERE `sessionId` IS NULL
AND ...
LIMIT bbb
将aaa
替换为当前会话ID,将...
替换为选择正确行所需的条件。将bbb
替换为您需要获取的行数。如果需要按特定顺序处理行(如果其中某些行的优先级高于其他顺序),请添加ORDER BY
子句。您还可以在status = ...
子句中添加UPDATE
以更改所获取行的状态(至pending
fe),以使代码的其他实例知道现在正在处理这些行。 / p>
上面的查询获取了一些行。接下来,运行:
SELECT *
FROM `tbl`
WHERE `sessionId` = 'aaa'
此查询获取要在客户端代码中处理的已获取行。
处理完每一行后,您DELETE
行或UPDATE
并将sessionId
设置为NULL
(释放行)和status
反映其新的地位。
此外,您应该在会话关闭时释放行(使用与上面相同的过程)。