【问题标题】:Does transactions lock tables or should I lock them in application code?事务会锁定表还是应该将它们锁定在应用程序代码中?
【发布时间】:2014-03-11 16:16:48
【问题描述】:

我有 2 张桌子 A 和 B。
在我的应用程序代码中,我更新了 A 中的一些行,然后使用我在表 A 中处理的行数更新表 B。
为了简单起见,我在我的应用程序代码中执行以下操作:

dbh->begin;   
my $amount =  0;   
foreach my $item (@item) {  
   my $row = dbh->do("UPDATE A SET VALUE = ?, STATUS = 'processed' WHERE STATUS <> 'processed' and ID = 12", under, $item->{amount});  
   $amount += $item->{amount} if($row);  
}  
if($amount) {  
   dbh->do("UPDATE B SET AMOUNT = ? WHERE id = ?", undef, $amount, 1234);  
}  
$dbh->commit; 

我保持简单(请忽略任何语法错误)来展示这个想法。
问题是:
当 2 个事务同时运行此代码时会发生什么?
理想情况下,我想以串行模式运行。我怎样才能做到这一点? MySQL 使用可重复读取对吗?

【问题讨论】:

    标签: mysql sql concurrency transactions


    【解决方案1】:

    事务会锁定表还是应该将它们锁定在应用程序代码中?

    由于您没有指定您使用的存储引擎,我将假设 InnoDB。 InnoDB uses row-level locking 内部事务(使用 InnoDB,您始终处于事务中,即使启用了自动提交模式)。您不必使用LOCK TABLES 手动锁定 InnoDB 表;执行语句时,相应的行将自动锁定。

    当 2 个事务同时运行此代码时会发生什么?

    通过事务,我假设您的意思是线程或进程。这是一种可能的情况:

    1. process1 首先执行UPDATE,锁定行ID = 12 在表A
    2. process2 尝试首先执行UPDATE,但行A.ID = 12 被锁定。等待解锁
    3. process1 执行第二个UPDATE,锁定行ID = 1234 在表B
    4. process1 提交事务,释放两个锁
    5. process2 获得行A.ID = 12 的锁定并运行UPDATE。由于该值已由 process1 更新,因此没有任何更改,第二个 UPDATE 被跳过
    6. process2 提交事务,释放锁

    请注意,在等待锁定时可能会超时。如果发生这种情况,超时的事务将是rolled back

    【讨论】:

    • 是的 InnoDB。超时被中止的事务,是否重启?
    • 您可以在应用程序中添加逻辑以重试失败的事务,但数据库引擎不会自动执行此操作。
    • 从教科书中,我读到交易失败的原因其他而不是代码错误被重新启动
    • 你有具体的例子吗?在服务器崩溃或关闭时不完整的事务是rolled back automatically(未重新启动)。由于锁定超时而失败的事务也是rolled back automatically
    • 嗯。我正在咨询的书(Silberschatz)说这种行为取决于实现。可能会重新启动或可能会杀死
    猜你喜欢
    • 1970-01-01
    • 2020-03-02
    • 2015-09-15
    • 1970-01-01
    • 2010-09-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多