gpt4 book ai didi

MySql:事务不检测死锁?

转载 作者:行者123 更新时间:2023-11-29 01:34:08 25 4
gpt4 key购买 nike

考虑以下 Perl 代码:

$schema->txn_begin();

my $r = $schema->resultset('test1')->find({id=>20});

my $n = $r->num;
$r->num($n+1);
print("updating for $$\n");
$r->update();

print("$$ val: ".$r->num."\n");

sleep(4);

$schema->txn_commit();

我期望由于更新受事务保护,因此如果两个进程尝试更新“num”字段,第二个进程应该会失败并出现一些错误,因为它输掉了比赛。 Interbase 将此称为“死锁”错误。然而,MySQL 会在 update() 调用上暂停,但会在第一个调用提交后继续。然后第二个进程具有 num 的“旧”值,导致增量不正确。观察:

$ perl trans.pl  & sleep 1 ; perl trans.pl 
[1] 5569
updating for 5569
5569 val: 1015
updating for 5571
5571 val: 1015
[1]+ Done perl trans.pl

两种情况的结果值为“1015”。这怎么可能是正确的呢?

最佳答案

假设您使用 InnoDB 作为存储引擎,这是我所期望的行为。 InnoDB的默认事务隔离级别是REPEATABLE READ 。这意味着当您执行 SELECT 时,事务会获得 snapshot数据库在该特定时间的信息。快照将包含来自尚未提交的其他事务的更新数据。由于每个进程中的 SELECT 发生在任一提交之前,因此它们都会看到处于相同状态的数据库(num = 1014)。

要获得您期望的行为,您应该遵循 Lluis 的建议并执行 SELECT ... FOR UPDATE锁定您感兴趣的行。为此,请更改此行

my $r = $schema->resultset('test1')->find({id=>20});

到此

my $r = $schema->resultset('test1')->find({id=>20}, {for=>'update'});

并重新运行测试。

如果您不熟悉 MySQL 中复杂的事务,我强烈建议您阅读文档中有关 InnoDB Transaction Model and Locking 的部分。 。另外,如果您还没有阅读过 DBIC Usage Notes关于事务和AutoCommit也非常仔细。当 AutoCommit 打开或关闭时,txn_ 方法的行为方式有点棘手。如果您愿意,我还建议您阅读源代码。就我个人而言,我必须阅读源代码才能完全理解 DBIC 在做什么,这样我才能得到我想要的确切行为。

关于MySql:事务不检测死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1942418/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com