select ... for update中没有最新的行

时间:2014-03-18 21:42:45

标签: mysql perl dbi

我遇到一个问题,我正在运行一个执行涉及两个表UsersTransactions的事务的Web服务。问题是,当我从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表上的select返回最近一行。但是,在第三个请求中,它无法再找到最近的行。当我这样做时:

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

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

我不确定我是否正确处理锁定。我正在用Users锁保护select ... for update表,但我没有为Transactions表执行此操作。我不确定这是否重要。由于我将更新嵌套到Transactions表的select ... for update中的Users表,我认为它会在事务中受到保护。

有关Transactions表上的选择未返回最新行的原因的任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:3)

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

您可以通过更改隔离级别(可能是“read committed”(Oracle的默认值))或在select开始新事务之前发出提交来避免此问题。