【发布时间】:2013-07-23 17:16:36
【问题描述】:
我正在运行一些简单的脚本来测试我正在解决的完整性问题的可能解决方案。假设我有一张桌子my_table
|foo |
|1 |
我有这两个sn-ps:
// db_slow.php
<?php
$db = new PDO('mysql:host=localhost;dbname=my_playground;charset=utf8', 'root', '');
echo 'starting transaction<br />';
$db->beginTransaction();
$stmt = $db->query('select * from my_table for update');
$rows = $stmt->fetchAll();
echo 'count tables: ', count($rows), '<br />';
if (count($rows) == 1) {
sleep(10);
$db->query('insert into my_table(foo) VALUES(2)');
}
$db->commit();
echo 'done';
// db_fast.php
<?php
$db = new PDO('mysql:host=localhost;dbname=my_plyaground;charset=utf8', 'root', '');
echo 'starting transaction<br />';
$db->beginTransaction();
$stmt = $db->query('select * from my_table for update');
$rows = $stmt->fetchAll();
echo 'count tables: ', count($rows), '<br />';
if (count($rows) == 1) {
$db->query('insert into my_table(foo) VALUES(3)');
}
$db->commit();
echo 'done';
db_slow.php 有 10 秒的延迟来模拟竞态条件。
据我了解,select ... for update 会锁定它选择的所有行。如果我运行db_slow,那么db_fast、db_fast 也会有10 秒的延迟,因为它正在等待db_slow,正如我所料。
但是,我没有得到的是输出:
// db_slow.php
starting transaction
count tables: 1
done
// db_fast.php
starting transaction
count tables: 2
done
还有my_table
|foo |
|1 |
|2 |
据我了解,select ... for update 锁定了为该事务选择的所有行。所以这就是我所期望的:
- db_slow:选择第 1 行并锁定它
- db_slow: 看到只有 1 行,等待
- db_fast:尝试选择第1行,看到它被锁定,等待
- db_slow: 用 '2' 插入行
- db_fast:继续,因为第 1 行已解锁
- db_fast:只选择了 1 行,所以插入了 '3'
- 以
foo: 1, 2, 3结尾
上面描述的输出和延迟似乎确认了步骤1、2、3、4。似乎db_fast在尝试获取锁后正在运行select?我以为它会选择一行,然后锁定或等待。
有点相关的问题:
当我使用select ... lock in share mode 运行它时,我最终会得到
// db_slow.php
starting transaction
count tables: 1
done
// db_fast.php
starting transaction
count tables: 1
done
还有my_table
|foo |
|1 |
|3 |
为什么db_slow 认为表中只有 1 行(插入行的条件)却不插入行 '2'?
【问题讨论】:
-
for update应该在您的代码中某处吗? -
一个连接到 my_playground,另一个连接到 adrian_playground_alpha - 错字?
-
@sgroves 废话,之前尝试过
lock in share mode,但忘了改回来。这很尴尬,但是当我将其更改为for update时,也会发生类似的事情。 @Alden 抱歉修复了它,它们在同一个数据库上运行,有多个脚本并忘记修复粘贴在这里的所有不一致 -
嗯,这很有趣,我希望输出为 1、2,而不仅仅是 1、3。
SELECT ... FOR UPDATE从读取到慢速完成,速度很快,所以应该看到计数为 2。 -
关于共享模式的问题,您是否遇到任何错误?从您的输出来看,两个脚本似乎都只计算了 1 行。他们应该都发送了他们的插入语句。其他东西正在回滚 db_slow 的更改。应该有错误信息。
标签: php mysql sql transactions data-integrity