Rails开发细节《四》Transactions事务

事务在数据库应用开发中是相当重要的,尤其是在关系数据库中。典型的例子就是银行在转账,在两个账户之间转账。

 

 
  
  1. account1.deposite(100) 
  2.  
  3. account2.withdraw(100) 

在ActiveRecord中使用transaction方法执行一段block来实现事务。在block的最后,会提交事务,更新数据库,如果在block中发生异常,数据库会回滚所有改变。

 

 
  
  1. Account.transaction do 
  2.   account1.deposite(100) 
  3.  
  4.   account2.withdraw(100) 
  5. end 

下面是一个完整的例子,我们创建一个表格,有两个字段:账号和余额。

定义一个Account类,包含deposit存钱和withdraw取钱两个方法。

 
  
  1. create_table :accounts:force => true do |t| 
  2.   t.string :number 
  3.   t.decimal :balance:precision => 10, :scale => 2, :default => 0 
  4. end 
  5.  
  6. class Account < ActiveRecord::Base 
  7.   validate :price_must_be_at_least_a_cent 
  8.  
  9.   def withdarw(amount) 
  10.     adjust_balance_and_save(-amount) 
  11.   end 
  12.  
  13.   def deposit(amount) 
  14.     adjust_balance_and_save(amount) 
  15.   end 
  16.  
  17.   def adjust_balance_and_save(amount) 
  18.     self.balance += amount 
  19.     save! 
  20.   end 
  21.  
  22.   def price_must_be_at_least_a_cent 
  23.     errors.add(:balance"is negative"if balance < 0 
  24.   end 
  25. end 
  26.  
  27. peter = Account.create(:balance => 100, :number => "12345"
  28. paul = Account.create(:balance => 200, :number => "23456"
  29.  
  30. Account.transaction do 
  31.   paul.deposit(10) 
  32.   peter.withdraw(10) 
  33. end 

我们可以通过

select * from accounts

查询一下数据,看看账户信息是否正确。

 
  
  • peter = Account.create(:balance => 100, :number => "12345"
  • paul = Account.create(:balance => 200, :number => "23456"
  •  
  • Account.transaction do 
  •   paul.deposit(350) 
  •   peter.withdraw(350) 
  • end

再来试试异常的情况,再来查查数据库,看看数据有没有回滚到初始值。

在异常的情况下,我们输出model对象的值看看。

 

 
  
  1. puts "Paul has #{paul.balance}" 
  2. puts "Peter has #{peter.balance}" 

我们会发现虽然数据库没有破坏,但是model对象的值被修改了。这是因为ActiveRecord没有跟踪对象的状态变化,事实上它也做不到。如果在你的应用中这是一个问题的话,你可以求助于object_transactions插件。

 




本文转自 virusswb 51CTO博客,原文链接:http://blog.51cto.com/virusswb/1016556,如需转载请自行联系原作者