我正在构建一个用户可以提交帖子的应用程序,人们可以回复帖子。当用户发帖时,他可以选择哪些用户可以查看帖子。
这是帖子表:
| 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。交易甚至是必要的,因为什么都没写?这会改变第一个答案吗?
最后,另一个问题。如果我有一个事务在插入之前检查某行是否存在,那么事务是否会阻止另一个事务在行检查和插入之间插入一行?
谢谢!
答案 0 :(得分:1)
我的问题是,是否因为交易而需要锁定。
简短的回答是肯定的,你做到了。
如果跟踪内容失败,那么所有交易都会给你回滚的方法。没有锁,就无法知道在两个查询之间的时间是否修改了基础表。
请注意,假设您正在使用InnoDB,您的SELECT ... LOCK IN SHARE MODE
只会锁定所选行而不是整个表格as documented here。 我强烈建议您阅读本文档,特别是两种方法之间的区别以及何时使用每种方法。
同样的概念也适用于你的第二个问题,并且得到了很好的解释here in this answer。
最后,归结为:
锁定会阻止其他人干扰任何数据库记录 你正在处理。交易保持任何&#34;之后&#34;来自的错误 干扰&#34;早期&#34;你做过的事情。没有一个可以 保证事情最终成功。但他们在一起。
明天的教训:僵局的喜悦。