`
hideto
  • 浏览: 2666813 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Rails源码研究之ActiveRecord:三,Transactions

    博客分类:
  • Ruby
阅读更多
这次我们分析一下Rails的事务支持
1,Rails默认将父子关系的表的save()和destroy()包装在一个事务里(见AWDWR一书的Transactions)
这保证了父子保存和删除的原子性,即ActiveRecord是级联保存和级联删除的,有源码为证
transactions.rb:
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


mysql_adapter.rb:
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


如果我们想给自定义的方法添加事务控制,有如下三种情况:
1,block transaction
def some_method
  transaction do
    david.withdrawal(100)
    mary.deposit(100)
  end
end

transaction方法后的block里的操作保持原子性

2,Object-level transaction
def some_method
  Account.transaction(from, to) do
    from.withdraw(100)
    to.deposit(100)
  end
end

这种情况下不仅数据库表有事务回滚,对象状态也有事务回滚
不过现在Rails去掉object transactions
如果你仍然想使用object transactions,可以使用object_transactions插件

3,Across database connections
def some_method
  Student.transaction do
    Course.transaction do
      course.enroll(student)
      student.units += course.units
    end
  end
end

但是这样做很难保证不同表的状态,ActiveRecord也不打算做multiple database的transaction,建议不要使用这种方式

我们再看看用到transactions的一些地方
association_collection.rb:
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


has_many_through_association.rb:
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
分享到:
评论

相关推荐

    rails_async_migrations:对ActiveRecord :: Migration的异步支持

    RailsAsyncMigrations ActiveRecord::Migration扩展程序以一种简单直接的方式使您的迁移异步。动机创建该库的目的是为了帮助在技术水平上难以扩展的小型公司。 小型项目不需要异步迁移队列,大公司在遇到扩展问题时...

    Rails的精简版本Rails::API.zip

    Rails::API 是 Rails 的精简版本,针对不需要使用完整 Rails 功能的开发者。 Rails::API 移除了 ActionView 和其他一些渲染功能,不关心Web前端的开发者可更容易、快速地开发应用程序,因此运行速度比正常的 Rails ...

    userstamp, 这个 Rails 插件扩展ActiveRecord.zip

    userstamp, 这个 Rails 插件扩展ActiveRecord Userstamp插件( v-2.0 )概述Userstamp插件扩展了 ActiveRecord::Base,以添加对'创建者','更新程序'和'deleter'属性的自动更新。 它是基于 ActiveRecord::Timesta

    to_xls-rails:将Rails ActiveRecord或Mongid数据导出到Excel文件

    数组元素支持对象:ActiveRecord,Mongid,哈希。 在您的Gemfile中: gem 'to_xls-rails' # Last officially released gem # gem "to_xls-rails", :git =&gt; "git://github....

    ROR绿色最新环境(2013/3/10)

    Rails::Rack::Logger ActionDispatch::ShowExceptions ActionDispatch::DebugExceptions ActionDispatch::RemoteIp ActionDispatch::Reloader ActionDispatch::Callbacks ActiveRecord::ConnectionAdapters::...

    ActiveRecord简单实例_activerecord.zip

    在Ruby on Rails框架中,ActiveRecord是一个至关重要的组件,它负责模型(Model)与数据库之间的交互。本实例将深入探讨ActiveRecord的基本用法,帮助理解如何在实际开发中有效地运用这个强大的工具。 首先,让我们...

    ActiveRecord-Without-Rails:只是在没有Rails的情况下使用ActiveRecord迁移的简单示例

    没有Rails的ActiveRecord 只是在没有Rails的情况下使用ActiveRecord迁移的简单示例您可以执行的任务: rake db:create rake db:migrate rake db:dropRails 5+的注意事项请注意,即使使用Rails 5,您也需要rake db:...

    stateful_enum:基于ActiveRecord :: Enum构建的非常简单的状态机插件

    stateful_enum是建立在ActiveRecord的内置ActiveRecord :: Enum之上的状态机gem。 安装 将此行添加到您的Rails应用程序的Gemfile中: gem 'stateful_enum' 和捆绑。 动机 您不需要抽象 stateful_enum取决于...

    枚举:具有I18n和ActiveRecordMongoid支持的枚举属性

    Rails 5.2+用法基本: class User extend Enumerize enumerize :sex , in : [ :male , :female ]end 请注意,枚举值仅是标识符,因此,如果要使用多字等值,则应使用I18n功能。 ActiveRecord: class CreateUsers &...

    Rails项目源代码

    这个Rails项目提供了学习和研究Web开发的机会,特别是对于Ruby on Rails新手,可以通过阅读和理解源代码来提升技能,了解实际应用中Rails的用法。同时,对于有经验的开发者,这个项目也可以作为一个起点,进行二次...

    Ruby on Rails中的ActiveRecord编程指南

    ### Ruby on Rails中的ActiveRecord编程指南 #### 一、引言 在Ruby on Rails框架中,ActiveRecord是一种用于实现数据库抽象层的对象关系映射(ORM)工具。它为开发人员提供了一种简单而强大的方式来处理数据库记录...

    paranoid2:Rails 4 的偏执模型

    Rails 4 定义了ActiveRecord::Base#destroy! 所以Paranoid2 gem 使用force: true arg 来强制销毁。 安装 将此行添加到应用程序的 Gemfile 中: gem 'paranoid2' 然后执行: $ bundle 用法 将deleted_at: ...

    rails-exporter-源码.rar

    《Rails Exporter 源码解析》 Rails Exporter 是一个用于 Rails 应用程序的开源工具,主要用于数据导出功能。源码分析将帮助我们深入理解其内部工作原理,以便更好地利用它来优化我们的应用。 一、Rails 框架基础 ...

    hashid-rails:在Rails应用程序ActiveRecord模型中使用Hashids(http:hashids.orgruby)

    在要启用哈希值的ActiveRecord模型中包括Hashid Rails。 class Model &lt; ActiveRecord :: Base include Hashid :: Rails end 继续使用Model#find输入hashid或常规的'ol id。 @person = Person . find ( params...

    workflow-activerecord:工作流库的 ActiveRecordRails 集成

    工作流库的 ActiveRecord/Rails 集成 工作流活动记录的主要+次要版本基于最旧的兼容 ActiveRecord API。 要在 Rails/ActiveRecord 4.1、4.2、5.0、5.1、5.2、6.0、6.1 中使用 ,请使用: gem 'workflow-...

    flowdock-rails:用于 ActiveRecord 模型的 Flowdock 通知程序

    Flowdock::Rails 这个 gem 添加了一个类方法来向特定流发送通知,以在启用的资源上创建和更新事件安装将此行添加到应用程序的 Gemfile 中: gem 'flowdock-rails'然后执行: $ bundle或者自己安装: $ gem install ...

    Ruby on Rails入门例子

    - **ActiveRecord查询接口(Query Interface)**:ActiveRecord提供了丰富的查询API,如`User.find(1)`, `Post.where(title: 'Hello')`,用于从数据库检索数据。 - ** erb语法**:在视图文件中,我们可以使用erb...

    Rails上的API:使用Rails构建REST APIAPIs on Rails: Building REST APIs with Rails

    1. **快速开发**:Rails内置了许多实用的功能和库,如ActiveRecord ORM、MVC架构等,这些都能够极大地加快开发进度。 2. **代码简洁**:Rails遵循“约定优于配置”的原则,这意味着开发者无需编写大量重复代码就能...

    Apress Pro ActiveRecord Databases with Ruby and Rails.pdf

    1. **自动化的表映射**:ActiveRecord可以根据类名自动推断出对应的数据库表名,并根据类属性推断出表中的列。 2. **数据验证**:提供了丰富的验证规则,如唯一性验证、存在性验证等,确保数据的完整性和一致性。 3....

    Ruby on Rails入门经典代码

    Ruby on Rails,简称Rails,是基于Ruby语言的一个开源Web应用程序框架,它遵循MVC(Model-View-Controller)架构模式,旨在使Web开发过程更加高效、简洁。本压缩包中的"Ruby on Rails入门经典代码"提供了新手学习...

Global site tag (gtag.js) - Google Analytics