2014-01-17 25 views
4

例子:爲什麼持續?在ActiveRecord :: Rollback之後返回true?

BillingProfile.transaction do 
    if @billing_profile.save 
    unless SomeService.do_something # returns false and rollback occurs 
     raise ActiveRecord::Rollback 
    end 
    end 
end 

@billing_profile.persisted? # Still return true, despite rollback 
@billing_profile.id # Is set, despite rollback 

爲什麼不@billing_profile的狀態反映該紀錄是回滾?

這是一個問題,因爲記錄在回滾後無法創建。

+0

您使用的是哪個版本的Rails?我不記得當我能夠複製您的問題時,我嘗試了這個版本。但我現在在軌道2和3.2上嘗試它,但我得到了適當的回滾。 – jvnill

+1

Rails 4.我將此報告爲ActiveRecord中的一個錯誤,該錯誤現在已經修復https://github.com/rails/rails/issues/13744 – mwalsher

回答

3

原來這是ActiveRecord的一個bug(軌道4):https://github.com/rails/rails/issues/13744

現在已經固定。

+1

我擊中這與軌道5.0.0.1 atm。我做了'@ model.save',這引發了一個數據庫錯誤,但仍然是'@ model.persisted?'返回'true'。瘋。我想會有一個單元測試。 – akostadinov

0

我對交易的工作方式感興趣。您的具體情況在docs中有解釋。引用文檔

事務調用可以嵌套。默認情況下,這會使嵌套事務處理塊中的所有數據庫 語句都成爲父事務處理的一部分 事務。例如,以下行爲可能令人驚訝:

User.transaction do 
    User.create(username: 'Kotori') 
    User.transaction do 
    User.create(username: 'Nemu') 
    raise ActiveRecord::Rollback 
    end 
end 

創建「琴」和「Nemu」。原因是ActiveRecord :: Rollback 在嵌套塊中的異常不會發出ROLLBACK。由於這些異常在事務塊中被捕獲,所以父塊 不能看到它並且實際的事務被提交。

爲了獲得嵌套事務的ROLLBACK,您可以通過傳遞requires_new:true來請求 真實的子事務。如果有任何錯誤 錯誤,數據庫將回滾到子交易 的開始位置,而不回滾父交易。如果我們把它添加到 前面的例子:

User.transaction do 
    User.create(username: 'Kotori') 
    User.transaction(requires_new: true) do 
    User.create(username: 'Nemu') 
    raise ActiveRecord::Rollback 
    end 
end 

只「小鳥」被創建。這適用於MySQL和PostgreSQL。 SQLite3 版本> ='3.6.8'也支持它。

大多數數據庫不支持真正的嵌套事務。在編寫 時,我們知道的唯一一個支持真實 嵌套事務的數據庫是MS-SQL。因此,Active Record 通過使用MySQL上的保存點和 PostgreSQL來模擬嵌套事務。有關保存點的更多信息,請參閱dev.mysql.com/doc/refman/5.6/en/savepoint.html以瞭解更多關於 的信息。

+1

添加requires_new:對事務的true無法爲我解決問題。該ID仍然設置並堅持?仍然是真實的。我的例子中也沒有嵌套事務;只有一個交易... – mwalsher

相關問題