【问题标题】:While in a transaction, how can reads to an affected row be prevented until the transaction is done?在事务中,如何在事务完成之前阻止对受影响行的读取?
【发布时间】:2012-04-27 15:44:14
【问题描述】:

我很确定这有一个简单的解决方案,但到目前为止我还没有找到它。提供了一个隔离级别设置为 SERIALIZABLE 的 InnoDB MySQL 数据库,并给出以下操作:

BEGIN WORK;
SELECT * FROM users WHERE userID=1;
UPDATE users SET credits=100 WHERE userID=1;
COMMIT;

我想确保一旦事务中的 select 发出,对应于 userID=1 的行就被锁定以供 reads 直到事务完成。就目前而言,如果事务正在进行,则对该行的 UPDATE 将等待事务完成,但 SELECT 只会读取先前的值。我知道这是这种情况下的预期行为,但我想知道是否有办法锁定行,这样 SELECT 也会等到事务完成返回值?

我正在寻找的原因是,在某些时候,如果有足够多的并发用户,可能会发生这样的情况:当前一个交易正在进行时,其他人会读取“信用”来计算其他内容。理想情况下,其他人运行的代码应该等待事务完成才能使用新值,否则可能会导致不可逆转的异步问题。

请注意,我不想锁定整个表以供读取,只锁定特定行。

另外,我可以在表中添加一个布尔“锁定”字段,并在每次开始事务时将其设置为 1,但我并不觉得这是这里最优雅的解决方案,除非绝对没有其他方式直接通过mysql处理。

【问题讨论】:

  • 您可以将表的快照放入临时表中:CREATE TEMPORARY TABLE t_users SELECT * FROM users;
  • 那不行,我想确保在事务进行时对特定行的读取被拒绝,创建临时表只有在我要从中删除行时才有帮助完成后将主表重新插入,但这听起来像访问数据库的次数过多。
  • 不好意思,我误解了你的问题。

标签: mysql transactions


【解决方案1】:

我找到了一个解决方法,具体来说:

SELECT ... LOCK IN SHARE MODE 在行上设置共享模式锁 读。共享模式锁使其他会话能够读取行,但 不要修改它们。 读取的行是最新的可用行,因此如果它们 属于另一个尚未提交的事务,读 阻塞直到该事务结束。

(Source)

似乎可以在依赖事务数据的关键 SELECT 语句中包含 LOCK IN SHARE MODE,它们确实会在检索行之前等待当前事务完成。为此,事务必须明确使用 FOR UPDATE(与我给出的原始示例相反)。例如,给定以下内容:

BEGIN WORK;
SELECT * FROM users WHERE userID=1 FOR UPDATE;
UPDATE users SET credits=100 WHERE userID=1;
COMMIT;

代码中我可以使用的任何其他地方:

SELECT * FROM users WHERE userID=1 LOCK IN SHARE MODE;

由于该语句未包装在事务中,因此锁会立即释放,因此对后续查询没有影响,但如果在事务中选择了涉及 userID=1 的行进行更新,则该语句将等到该事务完成了,这正是我想要的。

【讨论】:

    【解决方案2】:

    您可以尝试 SELECT ... FOR UPDATE 锁定读取。

    SELECT ... FOR UPDATE 读取最新的可用数据,在它读取的每一行上设置排他锁。因此,它设置的锁与搜索的 SQL UPDATE 在行上设置的锁相同。

    请浏览以下网站:http://dev.mysql.com/doc/refman/5.0/en/innodb-locking-reads.html

    【讨论】:

    • 已经尝试过,但它只锁定行进行写入,而不是读取;另外,如果隔离级别已经设置为 SERIALIZE,我相信这没有什么区别。
    • (由于某种原因我无法编辑之前的评论,但显然我的意思是 SERIALIZABLE )
    • 投了赞成票,因为它确实有助于找到解决方法(请参阅原始帖子)
    猜你喜欢
    • 1970-01-01
    • 2019-08-21
    • 1970-01-01
    • 2016-02-05
    • 2013-10-04
    • 2021-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多