MySQL - 在选择后立即更新某个列

时间:2015-06-21 09:56:41

标签: mysql

我遇到了问题,无法选择正确的解决方案。

我有一个 SELECT 查询,用于从表中选择记录。 这些记录的状态列如下所示。

<display-name>myApp</display-name>
    <welcome-file-list>
        <welcome-file>index.jsp</welcome-file>
    </welcome-file-list>

现在,在 SELECT 之后,我必须更新状态列。 我怎样才能避免竞争条件?

我想要实现的是,一旦某人(会话)选择了某些内容,在我不手动释放它之前,其他任何人都无法选择此内容(例如使用状态列)。

思想?

2 个答案:

答案 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反映其新的地位。

此外,您应该在会话关闭时释放行(使用与上面相同的过程)。