Mysql InnoDB读取时的行锁定

4
我已经阅读了MySQL文档,但可能并没有完全理解。我正在寻找的是从阅读中进行行锁定,当行被锁定时,我希望其他会话等待直到锁被释放。我不希望其他会话从快照中读取!他们必须等待直到释放为止!
我想得到的结果与以下示例完全相同,但只针对单个行而不是整个表格锁定:
START TRANSACTION
LOCK TABLES table1 WRITE
SELECT * FROM table1 WHERE id = 40912
UPDATE table1 SET column1 = 'value1' WHERE id = 40912
UNLOCK TABLES
COMMIT

提前感谢您!

3个回答

3

Elena Sharovar给出的答案是一种实现方式,但可能没有完全解释所需操作。 每个要执行SELECT的进程都需要使用相同字符串的GET_LOCK。如果这样做,MySQL将自动等待(最多指定秒数)直到另一个线程释放锁才返回结果。

以下是时间从上到下的发生情况:

          THREAD 1                                 THREAD 2
DO GET_LOCK("table1.40912", 30)
SELECT * FROM table1 WHERE id=40912     DO GET_LOCK("table1.40912", 30)
[UPDATE query]                          [automatically waits]
[UPDATE query]                          [automatically waits]
DO RELEASE_LOCK("table1.40912")         [lock finally obtained, query terminates]
                                        SELECT * FROM table1 WHERE id=40912

1

我还没有尝试过,但是可以使用MySQL函数GET_LOCK(str,timeout)和RELEASE_LOCK(str)来实现。这里的“str”是任何标识您锁定的字符串。

mysql_query('DO GET_LOCK("table1.40912", 60)')
mysql_query('SELECT * FROM table1 WHERE id = 40912')
mysql_query('UPDATE table1 SET column1 = 'value1' WHERE id = 40912')
mysql_query('DO RELEASE_LOCK("table1.40912")') 

嗨!感谢您的答复,但似乎它并没有起作用...另一个会话(选择)仍然返回快照中的值! - DarkSideOfTheMoon83

1
我对于这个有趣的问题(如何强制MySQL不读取快照,即使快照是一致的)最好的想法是使用“FOR UPDATE”来读取所有内容,就像“SELECT FOR UPDATE #select-clause#”一样。
然而,非常重要的是,这些选择使用非常窄的索引找到记录,这意味着它们锁定了它们所读取的内容。如果一个SELECT通过全表扫描或者使用WHERE(在EXPLAIN语句中)运行得太过频繁,那么长时间锁定大量表格区域可能会导致潜在的长反应时间。
我建议您在数据库抽象层中进行测试。
您可以在隔离文档中阅读有关此机制的所有信息。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接