【问题标题】:how to find the cause of ActiveRecord ROLLBACK如何找到 ActiveRecord ROLLBACK 的原因
【发布时间】:2012-01-30 06:08:34
【问题描述】:

在日志中我看到ROLLBACK,但没有记录异常。有没有办法找出导致 ROLLBACK 的原因?

这是日志的摘录:

  Phone Load (0.4ms)  SELECT "phones".* FROM "phones" WHERE "phones"."id" = $1 LIMIT 1  [["id", 980190963]]
   (0.2ms)  BEGIN
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."phone_id" = 980190963 LIMIT 1
   (0.2ms)  ROLLBACK
  Phone Load (0.4ms)  SELECT "phones".* FROM "phones" WHERE "phones"."id" = $1 LIMIT 1  [["id", 980190963]]
  User Load (0.4ms)  SELECT "users".* FROM "users" WHERE "users"."phone_id" = 980190963 LIMIT 1

【问题讨论】:

  • ROLLBACK 周围的日志中有什么内容?
  • 没有错误。此外,奇怪的是,它一次使用事务,下一次不使用。除非这两部分不相关。
  • 知道是什么导致了事务中的 SELECT 吗?
  • 可能你正在做一些保存/更新。能贴一下log对应的代码吗?
  • 解决了我的问题:rails 不喜欢在回调期间修改具有直通关联的关联模型时,无论是在模型中还是在观察者中。没有异常消息或任何东西;只是回滚。

标签: ruby-on-rails activerecord


【解决方案1】:

用 BANG '!' 保存记录所以它会产生一个运行时错误,你会知道它发生在哪里

【讨论】:

  • 我不知道。在我的情况下,我在destroy 上得到回滚,在这种情况下,所选答案似乎对我有帮助,但这个答案不适用。
  • 我希望我能多次投票。它多次救了我。
  • 谢谢老哥,我很快就找到了问题! (
【解决方案2】:

一种方法是手动将信息写入日志。从你的控制器尝试这样的事情:

Rails.logger.info(@your_object.errors.inspect) 

这应该输出所有失败的验证的内容。

【讨论】:

    【解决方案3】:

    1) 禁用 before_create、before_save、before_update 并检查它的保存位置

    2) 如果回滚是由其中一种方法引起的,请在您不打算回滚时检查这些方法是否返回 true。

    例如,如果您为布尔字段设置默认值以避免为零,您可能会这样做

    def set_defaults_before_create
      self.my_boolean_field ||= false
    end
    

    在此示例方法中,set_defaults_before_create 始终返回 false,从而回滚您的事务。所以重构它以返回 true

    def set_defaults_before_create
      self.my_boolean_field ||= false
      true
    end
    

    【讨论】:

    • 我花了大约一天的时间来调试这个问题。非常感谢:)
    • 第二点解决我的问题。方法需要返回true,我认为它用于验证目的,即使我们将它用于其他目的。
    • 我在模型中定义了一个函数destroy 时遇到了类似的问题,用于从磁盘中删除与记录相关的其他文件,然后如果文件丢失,该函数返回不正确,所以我在最后一行添加了true,一切都很好。谢谢!
    【解决方案4】:

    我想出的3个方法(1个失败)是

    1. 在所有相关保存、验证方法的活动记录上使用观察者

    2. 打开活动记录并在触发 ROLLBACK 的位置放置调试器语句,然后运行 ​​caller 以查明触发错误的代码。

    3. 失败:覆盖活动记录方法并暂停异常。如果我记得这个方法没有捕获任何异常,因为保存方法被包装在事务中。

    注意:仅在模式不是 Rails.env.production? 时启用。在 Rails 3.2.13 上测试,使用 ruby​​ 1.9.3。

    1. 观察者:http://guides.rubyonrails.org/v3.2.13/active_record_validations_callbacks.html#observers

      类 ActiveRecordObserver <:observer>

      observe "ActiveRecord::Base"
      
      def after_validation(model)
          debugger if model.errors.messages.any?
          Rails.logger.error "after validation"
      end
      def before_update(model)
          debugger if !model.valid?
          Rails.logger.error "before update"
      end
      def after_update(model)
          debugger if !model.valid?
          Rails.logger.error "after update"
      end
      def before_save(model)
      
          debugger if model.errors.messages.any?
          Rails.logger.error "#{model}"
          Rails.logger.error "before save"
      end
      def after_save(model)
          debugger if model.errors.messages.any?
          Rails.logger.error "after save"
      end
      

      结束

    注意:要在最新的 Rails 版本(从 v.4 到最新的 v.6)中使用观察者,您需要将 gem 'rails-observers' 捆绑到 Gemfile 中(最好包含在 :development 和 :test 组中),将类放在app/observers/active_record_observer.rb 下,并通过放置(或添加到)以下行在您当前的环境配置文件(例如config/environments/development.rb)中注册观察者:config.active_record.observers = [:active_record_observer]

    2) https://github.com/rails/rails/blob/3-1-stable/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb#L231 cd `bundle show activerecord`

         Put a debugger statement when where the rollback is executed.
        /Users/<user>/.rvm/gems/ruby-1.9.3-<env>/gems/activerecord-3.2.14/lib/active_record/connection_adapters/abstract/database_statements.rb
    
       196              transaction_open = false
       197              decrement_open_transactions
       198              if open_transactions == 0
       199                rollback_db_transaction
       200                debugger
    => 201                rollback_transaction_records(true)
       202              else
       203                rollback_to_savepoint
       204                debugger
       205                rollback_transaction_records(false)
    

    当 Rails 服务器或控制台命中 caller 中的断点类型时,获取回溯。

    1. 在开发模式下覆盖 AR。 TODO:仅在 !Rails.env.production 时覆盖? 把这个放在app/config/initializers/active_record_or_any_file_name.rb

      ActiveRecord::Base.class_eval 做 别名方法 :old_save, :save 别名方法 :old_save!, :save! 默认保存(*args) 开始 放“#{self}保存” Rails.logger.info "#{self} 保存" old_save(*args) 救援异常 => e 调试器 放电子 结尾 结尾 def 保存!(*args) 开始 Rails.logger.info "#{self} 保存!" 放“#{self}保存!” old_save!(*args) 救援异常 => e 调试器 放电子 结尾 结尾 结束

    【讨论】:

    • 我有一个类似的问题,回滚不是由于任何异常,因此没有救援块会给出原因。按照@davidtimgsu 的建议放置调试点有助于将其本地化。在 ActiveRecord 5.2.3 中,active_record/connection_adapters/abstract/transaction.rb 下有一行显示为Thread.current.status == "aborting"。这是我的回滚的原因,因为外部进程正在终止当前线程,并且当前线程中的确保语句中的所有事务都正在回滚。
    • 要在 Rails 中使用 Observers 超过版本 4(直到最新的 v.6),您需要在 Gemfile 中捆绑 gem 'rails-observers',将类放在 app/observers/active_record_observer.rb 下,并在您当前的环境配置文件(例如 config/environments/development.rb 通过放置(或添加到)此行:config.active_record.observers = [:active_record_observer]
    猜你喜欢
    • 2019-02-03
    • 1970-01-01
    • 2011-04-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-19
    • 2016-08-28
    • 2021-09-02
    相关资源
    最近更新 更多