【问题标题】:Latest rows not available in select ... for update选择中不可用的最新行...进行更新
【发布时间】:2014-03-18 21:42:44
【问题描述】:

我有一个问题,我正在运行一个 Web 服务,该服务正在执行涉及两个表 UsersTransactions 的事务。问题是当我从Transactions 中选择时,有时无法找到最新的行,我可以看到它存在于数据库中。

我使用 Perl/Dancer 作为 Web 框架,尽管我认为我遇到的问题是在数据库级别(我使用的是 MySQL/InnoDB)。伪代码如下所示:

my $dbh = DBI->connect_cached(("DBI:mysql:Database;host=localhost;mysql_ssl=1",
                 "user", "password",
                 {RaiseError => 0, AutoCommit => 0});
my $sth_transact = $dbh->prepare("select balance from Users ".
                  "where id=? for update");

... store result in local variable ...

my $sth_inner = $dbh->prepare("select deposit from Transactions ".
                   "where id=?");

$sth_inner->execute();
if (my $deposit = $sth_inner->fetch_row()) {
     $deposit *= $bonus;

     $sth_inner = $dbh->prepare("update Transactions set deposit=?".
                                "where id=?");
     $sth_inner->bind_param(1, $deposit);
     $sth_inner->bind_param(2, $transaction_id);
     $sth_inner->execute();

     ... update balance in Users table ...
}

在前几个请求中,Transactions 表上的选择返回最新的行。但是,在第三个请求中,它不再能找到最近的行。当我这样做时:

my $sth_inner = $dbh->prepare("select id from Transactions where id=(SELECT max(id) from Transactions)");

它返回比最近行早 3 行的 id。例如,如果Transactions 表中有 87 行,它将返回 84。

我不确定我是否错误地处理了锁定。我用select ... for update 锁保护Users 表,但我没有为Transactions 表这样做。我不确定这是否重要。由于我将Transactions 表的更新嵌套在Users 表的select ... for update 中,因此我认为它会在事务中受到保护。

感谢任何有关 Transactions 表上的选择未返回最新行的帮助。

【问题讨论】:

  • 你能显示你省略的代码吗?
  • 如果我只是在“从交易中选择存款”查询中添加“... for update”,它就会解决问题。虽然我不确定我是否理解为什么会这样,以及为什么我需要锁定两个表。
  • 添加了一些省略的代码。主要问题是它永远不会进入 if 语句,因为给定 id 的行似乎对它不可用(即使它在数据库中)。

标签: mysql perl dbi


【解决方案1】:

此问题通常是由 InnoDB 的默认隔离级别“可重复读取”引起的。这意味着在当前事务启动后,连接无法看到添加到数据库中的任何内容。

您可以通过更改隔离级别(可能更改为“读取已提交”,这是 Oracle 的默认设置)或在您选择开始新事务之前发出提交来避免此问题。

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-03-14
  • 2013-10-15
  • 1970-01-01
  • 1970-01-01
  • 2013-07-29
  • 2021-01-04
相关资源
最近更新 更多