【发布时间】:2014-03-18 21:42:44
【问题描述】:
我有一个问题,我正在运行一个 Web 服务,该服务正在执行涉及两个表 Users 和 Transactions 的事务。问题是当我从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 的行似乎对它不可用(即使它在数据库中)。