Rails源码研究之ActiveRecord:三,Transactions

这次我们分析一下Rails的事务支持
1,Rails默认将父子关系的表的save()和destroy()包装在一个事务里(见AWDWR一书的Transactions)
这保证了父子保存和删除的原子性,即ActiveRecord是级联保存和级联删除的,有源码为证
transactions.rb:
[code]
module ActiveRecord
module Transactions
def self.included(base)
base.extend(ClassMethods)
base.class_eval do
[:destroy, :save, :save!].each do |method|
alias_method_chain method, :transactions
end
end
end

module ClassMethods
def transaction(*objects, &block)
previous_handler = trap('TERM') { raise TransactionError, "Transaction aborted" }
increment_open_transactions

begin
unless objects.empty?
ActiveSupport::Deprecation.warn "Object transactions are deprecated and will be removed from Rails 2.0. See http://www.rubyonrails.org/deprecation for details.", caller
objects.each { |o| o.extend(Transaction::Simple) }
objects.each { |o| o.start_transaction }
end

result = connection.transaction(Thread.current['start_db_transaction'], &block)

objects.each { |o| o.commit_transaction }
return result
rescue Exception => object_transaction_rollback
objects.each { |o| o.abort_transaction }
raise
ensure
decrement_open_transactions
trap('TERM', previous_handler)
end
end

private
def increment_open_transactions #:nodoc:
open = Thread.current['open_transactions'] ||= 0
Thread.current['start_db_transaction'] = open.zero?
Thread.current['open_transactions'] = open + 1
end

def decrement_open_transactions #:nodoc:
Thread.current['open_transactions'] -= 1
end
end

def transaction(*objects, &block)
self.class.transaction(*objects, &block)
end
end
end
[/code]

mysql_adapter.rb:
[code]
module ActiveRecord
module ConnectionAdapters
class MysqlAdapter < AbstractAdapter
def begin_db_transaction #:nodoc:
execute "BEGIN"
rescue Exception
# Transactions aren't supported
end

def commit_db_transaction #:nodoc:
execute "COMMIT"
rescue Exception
# Transactions aren't supported
end

def rollback_db_transaction #:nodoc:
execute "ROLLBACK"
rescue Exception
# Transactions aren't supported
end
end
end
end
[/code]

如果我们想给自定义的方法添加事务控制,有如下三种情况:
1,block transaction
[code]
def some_method
transaction do
david.withdrawal(100)
mary.deposit(100)
end
end
[/code]
transaction方法后的block里的操作保持原子性

2,Object-level transaction
[code]
def some_method
Account.transaction(from, to) do
from.withdraw(100)
to.deposit(100)
end
end
[/code]
这种情况下不仅数据库表有事务回滚,对象状态也有事务回滚
不过现在[url=http://dev.rubyonrails.org/changeset/6439]Rails去掉object transactions[/url]
如果你仍然想使用object transactions,可以使用[url=http://code.bitsweat.net/svn/object_transactions/]object_transactions[/url]插件

3,Across database connections
[code]
def some_method
Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end
end
[/code]
但是这样做很难保证不同表的状态,ActiveRecord也不打算做multiple database的transaction,建议不要使用这种方式

我们再看看用到transactions的一些地方
association_collection.rb:
[code]
module ActiveRecord
module Associations
class AssociationCollection < AssociationProxy

def <<(*records)
result = true
load_target

@owner.transaction do
flatten_deeper(records).each do |record|
raise_on_type_mismatch(record)
callback(:before_add, record)
result &&= insert_record(record) unless @owner.new_record?
@target << record
callback(:after_add, record)
end
end

result && self
end

end
end
end
[/code]

has_many_through_association.rb:
[code]
module ActiveRecord
module Associations
class HasManyThroughAssociation < AssociationProxy

def create!(attrs = nil)
@reflection.klass.transaction do
self << @reflection.klass.with_scope(:create => attrs) { @reflection.klass.create! }
end
end

end
end
end
[/code]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值