【问题标题】:How to deliberately lock a MySQL row such that even SELECT will return an error?如何故意锁定 MySQL 行,这样即使 SELECT 也会返回错误?
【发布时间】:2011-02-22 18:30:46
【问题描述】:

我正在尝试使用 MySQL 行锁定来基本上在一行上模拟 MuteEx。假设我的表有 2 列,一个 id 和一个文本字段,以及三个条目 (1,a) (2,b) 和 (3,c)。 选择 * FROM 表;将返回这些结果。 我可以按正常方式锁定特定行。

START TRANSACTION;
BEGIN;
SELECT * FROM table WHERE id = '2' FOR UPDATE;

但是,如果从第二个连接我要从表中选择 *。它将返回所有 3 个结果。有没有办法让行级锁定基本上防止任何 SELECT 看到/使用被锁定的行?基本上,我试图阻止任何人使用当前正在使用/操作的行,甚至将行视为其数据(因为它正在被使用/操作)在 SELECT 时不能被信任是准确的.

【问题讨论】:

  • 可能不是你(或我)想听到的,但看起来如果第二个选择器也使用SELECT ... FOR UPDATE,它会等到初始锁定被释放。

标签: mysql locking innodb


【解决方案1】:

如果您将事务隔离级别设置为SERIALIZABLEInnoDB 将隐式附加LOCK IN SHARE MODE 到所有SELECT 语句。

此模式与SELECT FOR UPDATE 放置的锁冲突,SELECTs 将锁定。

但请注意,InnoDB 可能会锁定比满足WHERE 条件更多的行。这是因为它锁定了所有扫描的行,而不仅仅是那些匹配的

假设您在col1 上有一个索引,并且这个查询:

SELECT  *
FROM    mytable
WHERE   col1 = 1
        AND col2 = 2
FOR UPDATE

使用这个索引。

这将锁定 所有 带有 col1 = 1 的记录,即使是带有 col2 <> 2 的记录

【讨论】:

    【解决方案2】:

    您需要LOCK IN SHARE MODE。将它与 SELECT 一起使用可以保证没有其他人使用 FOR UPDATE 锁定任何行。

    例如

    客户 A 做SELECT * FROM table WHERE type=2 FOR UPDATE

    客户端 B 执行 SELECT * FROM table LOCK IN SHARE MODE 并挂在这里

    客户端 A 写入/插入/更新某些内容,然后执行 COMMIT

    客户端 B 现在解冻并恢复处理

    【讨论】:

      【解决方案3】:

      实际上,行数据可以在你操作的时候被信任。

      如果您从一个连接启动事务,则在您提交事务之前,其他连接不会看到您的任何更改。

      【讨论】:

        【解决方案4】:

        我不知道是否有本地的锁定特定机制来执行此操作,但我的第一个要求是给表一个状态列(例如locked)并在锁定时将其设置为1排。对此敏感的select 将始终向任何查询添加WHERE locked != '1' 条件。

        顺便说一句,我不知道你在做什么,但这不是应该比数据库引擎高一两级的任务吗?

        【讨论】:

        • 我只是好奇这是否可以从数据库中获取。因为我目前的方法感觉有点笨拙。该项目是多线程的,每个线程都需要从数据库中选择工作(工作不断从几个不同的区域添加),但是,没有两个线程应该同时尝试相同的工作,所以我目前的解决方案是互斥锁一个选择可用工作的函数,然后专门更新这些行以说明它们在释放互斥锁之前正在工作。我想我已经在做最好的解决方案了。
        猜你喜欢
        • 1970-01-01
        • 2018-05-13
        • 2021-03-24
        • 2021-07-06
        • 2020-03-20
        • 1970-01-01
        • 2017-09-07
        • 2019-07-07
        • 2012-12-08
        相关资源
        最近更新 更多