rails實現「事務」的方法

2021-09-21 21:19:56 字數 2104 閱讀 7105

在學習資料庫時,曾經提到事務,最典型的乙個例項就是銀行轉賬的問題。

a帳戶向b帳戶轉賬100塊,這個事情一定要發生兩件事情,a的帳戶上減去100塊,b的賬戶上加上100塊。如果半路發生問題而中斷這個事情,那麼必須回滾到初始狀態。

下面來看一下用rails來實現這個例子:

首先,建立模型類account, 資料遷移:

在account類中定義方法:

實施資料遷移。執行console

>> peter = account.create(:balance=>100, :number=>"12345")

>> paul = account.create(:balance=>200, :number=>"54321")

#create直接建立並儲存到accounts表中

現在資料庫中的內容#select * from account_development.account

繼續在console裡執行:

>> account.transaction do

?> paul.deposit(10)

>> peter.withdraw(10)

>> end

此時資料庫中的內容:

現在再來看看異常情況,1.從peter帳戶上轉350出去給peter

>> account.transaction do

?> paul.deposit(350)

>> peter.withdraw(350)

>> end

------

這時丟擲了異常:

activerecord::recordinvalid: validation failed: balance is negative!

---資料庫還是保持原樣:

2.從peter賬戶上轉10出去給tom

>> account.transaction do

?> paul.deposit(10)

>> tom.withdraw(10)

>> end

----丟擲異常:

nameerror: undefined local variable or method `tom' for #

資料庫依然保持原樣。

雖然資料庫依然保持原樣,但是模型物件會發生變化,look:

現在還是恢復原狀,peter有100塊,paul有200塊

現在執行:

結果出乎意料, 

transfer aborted!

paul has  550.0

peter has -250.0

模型物件已經被改變了!

原因就在於activerecord並沒有跟蹤物件在事務前後的狀態,實際上它也跟蹤不了, 因為沒有一種簡單的辦法可以知道哪些模型物件參與了事務。為了解決這個問題,我們可以把涉及一次事務的模型物件以引數的形式明確的告訴transaction

這次結果就跟我們料想的一樣了:

transfer aborted!

paul has  200.0

peter has 100.0

現在可以將轉賬的方法寫到account類中去了,一次轉賬涉及兩個帳戶, 並且不是由其中的任何乙個來發起的, 所以這個方法時乙個類方法, 接受兩個account物件作為引數:

試試在console下使用這個方法:

>> peter=account.find(1)

>> paul=account.find(2)

>> account.transfer(peter, paul, 350) rescue puts "transfer aborted!"

#結果:

#transfer aborted!

=> nil

------

>> puts "paul has #"

#結果paul has 200.0

=> nil

------

>> puts "peter has #"

#結果:

peter has 100.0

=> nil

-------

讓事務自動恢復物件狀態也有乙個缺點:你將無法獲知驗證過程**現的錯誤資訊,非法的物件不會被儲存,事務會將所有修改回滾,但沒有什麼簡單方法可以知道究竟**出了錯。

事務的實現

在很早的以前,我們要實現乙個事務通常是基於sql的資料庫事務,一般的通過sql查詢語言來實現,如下所示,同時更新兩本書的 begin transaction update tb book set price 122 where ident current 1001 update tb book se...

jedis實現redis事務方法exec返回空陣列

正題 先說我發現的問題 當乙個事務的執行被打斷,jedis的exec 為什麼沒有返回null,返回的是乙個empty list?static void rename final k key,final k newkey,redisoperationsoperations else while ope...

rails實現驗證碼

網上其實有一大堆這樣的資料了,我再寫也沒多大價值,談下幾個注意點吧。1.在windows上安裝rmagic,如果你是通過gem安裝的,require rmagic 要修改為 require rubygems require rmagick 才能正確引入。2.網上那個例子,畫布是使用rmagic內建的...