我正在运行一些简单的脚本来测试我正在解决的完整性问题的可能解决方案。假设我有一个表my_table
|foo |
|1 |
我有这两个片段:
// 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
会锁定为该事务选择的所有行。所以这就是我的期望:
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
没有插入行'2',即使它认为表中只有1行(插入行的条件)?
答案 0 :(得分:1)
我认为预期的行为有点偏差。在db_slow提交之前,表中的所有行都被锁定。提交后,有两行。 db_slow提交时,db_fast被解除阻塞。因此,行为是: