MySQL事务与锁定

时间:2014-05-19 01:32:38

标签: php mysql database transactions acid

我正在构建一个用户可以提交帖子的应用程序,人们可以回复帖子。当用户发帖时,他可以选择哪些用户可以查看帖子。

这是帖子表:

| id | poster-id | title | message | ... |

这是帖子可见表格。它代表帖子和成员之间的个人关系(这种关系意味着他们可以查看和回复帖子):

| id | post-id | user-id |

这是回复表:

| id | posts-id | poster-id | title | message | ... |

现在,当有人添加回复时,我会在交易中运行以下内容:

try
{
    $db->beginTransaction();
    // first check if the user is part of the posts-visible group
    $stmt = $db->prepare('SELECT id FROM `posts-visible` WHERE posts-id=:pid AND poster-id=:uid LOCK IN SHARE MODE');
    // ... bind and execute

    if($stmt->rowCount() <= 0) return false; // not in visible group

    $stmt = $db->prepare('INSERT INTO `replies` ... ');
    // binds and execute

    $db->commit();
}
catch(Exception $e)
{
    $db->rollback();
}

我的问题是:LOCK IN SHARE MODE是否必要?我设想了一种可能的竞争条件,其中原始海报在用户发布回复时删除了对用户的帖子的访问权限,其中尽管海报禁止他访问,他仍然可以发布回复,所以我放{{1这样其他会话就可以读取但不能修改它。但是,事务是否还不能保证通过ACID中的隔离进行同步访问,这种情况不会发生?如果是这样,LOCK IN SHARE MODE何时适合?为什么要在交易中使用它?

作为第二个问题,我还有一些代码可以获取有关帖子的信息(例如帖子内容,标题等)。代码是类似的,除了INSERT我在第一个检查访问权限的SELECT之后有另一个SELECT。交易甚至是必要的,因为什么都没写?这会改变第一个答案吗?

最后,另一个问题。如果我有一个事务在插入之前检查某行是否存在,那么事务是否会阻止另一个事务在行检查和插入之间插入一行?

谢谢!

1 个答案:

答案 0 :(得分:1)

  

我的问题是,是否因为交易而需要锁定。

简短的回答是肯定的,你做到了。

如果跟踪内容失败,那么所有交易都会给你回滚的方法。没有锁,就无法知道在两个查询之间的时间是否修改了基础表。

请注意,假设您正在使用InnoDB,您的SELECT ... LOCK IN SHARE MODE只会锁定所选行而不是整个表格as documented here我强烈建议您阅读本文档,特别是两种方法之间的区别以及何时使用每种方法。

同样的概念也适用于你的第二个问题,并且得到了很好的解释here in this answer

  

最后,归结为:

     

锁定会阻止其他人干扰任何数据库记录   你正在处理。交易保持任何&#34;之后&#34;来自的错误   干扰&#34;早期&#34;你做过的事情。没有一个可以   保证事情最终成功。但他们在一起。

     

明天的教训:僵局的喜悦。