Rails源码研究之ActiveRecord:三,Transactions

本文深入探讨了Rails框架中事务的支持方式及其实现原理,包括默认事务处理、自定义方法中的事务控制及不同场景下的应用示例。
这次我们分析一下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]
源码地址: https://pan.quark.cn/s/d1f41682e390 miyoubiAuto 米游社每日米游币自动化Python脚本(务必使用Python3) 8更新:更换cookie的获取地址 注意:禁止在B站、贴吧、或各大论坛大肆传播! 作者已退游,项目不维护了。 如果有能力的可以pr修复。 小引一波 推荐关注几个非常可爱有趣的女孩! 欢迎B站搜索: @嘉然今天吃什么 @向晚大魔王 @乃琳Queen @贝拉kira 第方库 食用方法 下载源码 在Global.py中设置米游社Cookie 运行myb.py 本地第一次运行时会自动生产一个文件储存cookie,请勿删除 当前仅支持单个账号! 获取Cookie方法 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 按刷新页面,按下图复制 Cookie: How to get mys cookie 当触发时,可尝试按关闭,然后再次刷新页面,最后复制 Cookie。 也可以使用另一种方法: 复制代码 浏览器无痕模式打开 http://user.mihoyo.com/ ,登录账号 按,打开,找到并点击 控制台粘贴代码并运行,获得类似的输出信息 部分即为所需复制的 Cookie,点击确定复制 部署方法--腾讯云函数版(推荐! ) 下载项目源码和压缩包 进入项目文件夹打开命令行执行以下命令 xxxxxxx为通过上面方式或取得米游社cookie 一定要用双引号包裹!! 例如: png 复制返回内容(包括括号) 例如: QQ截图20210505031552.png 登录腾讯云函数官网 选择函数服务-新建-自定义创建 函数名称随意-地区随意-运行环境Python3....
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值