2014-03-18 61 views
3

我有一個問題,我正在運行一個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 ... 
} 

在前面的幾請求選擇的交易表中返回最近的行。但是,在第三個請求中,它不能再找到最近的行。當我這樣做的時候:

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表執行此操作。我不確定這是否重要。由於我將更新嵌套在Users表的select ... for update中的Transactions表中,我認爲它將在事務中受到保護。

爲什麼Transactions表上的選擇沒有返回最近的行的任何幫助表示讚賞。

+0

你能顯示你遺漏的代碼嗎? – ThisSuitIsBlackNot

+0

它出現,如果我只是添加「...爲更新」的「從交易選擇存款」查詢它解決了問題。儘管我不確定我是否理解爲什麼會出現這種情況,爲什麼我需要在兩個表上鎖定。 –

+0

添加了一些省略的代碼。主要的問題是它永遠不會輸入if語句,因爲給定id的行不可用(即使它在數據庫中)。 –

回答

3

此問題通常由InnoDB的默認隔離級別引起,該級別爲「可重複讀取」。這意味着在當前事務啓動後,連接無法看到添加到數據庫的任何內容。

您可以通過更改隔離級別(可能爲Oracle的默認讀取提交)或通過在您選擇開始新事務之前發出提交來避免此問題。

+0

有趣。所以在Perl中:$ dbh-> do(「SET TRANSACTION ISOLATION LEVEL READ COMMITTED」); –

+0

這裏是一個相關的SO問題:http://stackoverflow.com/questions/17248553/track-non-deterministic-mysql-errors-in-perl謝謝你把這個引起我的注意! –