【问题标题】:RoR: The right way of rescuing a DB exception on save?RoR:在保存时挽救数据库异常的正确方法?
【发布时间】:2016-07-19 15:58:56
【问题描述】:

我最近在尝试保存 ActiveRecord 模型后经常遇到我的数据库因Adaptive Server connection timed out 而失败的问题。

如果我尝试rescue 这个失败的尝试并再次保存对象,我会得到ActiveRecord::StaleObjectError,所以我必须重新创建从一开始就保存的对象,这可能是一个相当昂贵的过程。

鉴于我不能以任何方式影响数据库性能,在应用程序端处理这种情况的正确方法是什么?

【问题讨论】:

  • ActiveRecord::StaleObjectError 在存在乐观锁定时发送。您确定没有尝试并行修改记录吗?
  • @NicNilov,是的,这是肯定的。

标签: ruby-on-rails ruby-on-rails-3 activerecord


【解决方案1】:

重新加载是你想要的

begin
  object.save
rescue
  object.reload.save
end

类似的东西。这是它的文档:

http://apidock.com/rails/ActiveRecord/Persistence/reload

【讨论】:

  • 嗯,这就是我写的。重新加载后,我会在对对象进行任何更改之前将对象保持在数据库中的状态,因此我必须再次完成整个过程,这是我想要避免的。
  • 好吧,出于某种原因,我不清楚您只是尝试了基本的重新加载,或者这个特定的修复是不可取的。您的问题也不清楚为什么重新创建对象很昂贵,或者为什么您必须从头开始在内存中重新创建对象。
  • 好吧,不是重新创建对象本身是昂贵的,而是它的新状态导致它需要一些相当繁重的计算和网络交互。在将结果应用到模型之前,我可能会将结果缓存到其他地方,但这看起来更像是一种解决方法,而不是我的解决方案。我想知道如何以ActiveRecord 方式处理这个问题)
  • ActiveRecord 在这里无法为您提供帮助。听起来您有一些数据库性能问题需要由具有索引或其他东西的人解决。您还可以尝试使活动记录对象不那么复杂。或者最后,你可以像你说的那样缓存。将属性保存到变量并从那里开始。
【解决方案2】:

Adaptive Server connection timed out 错误是由于更新记录耗时过长。一种处理方法是增加database.yml 中的语句超时:

timeout: 10000 # milliseconds, default is 5000

这并不能直接解决问题,但可能有助于降低问题的频率。

如Active Record Query Interface Guide 中所述,乐观锁定仅在表中存在lock_version 字段时才有效。不清楚您是否首先需要锁定,但您的 Rails 显然已启用并正常工作。

由于lock_version 的值是触发ActiveRecord::StaleObjectError 的唯一因素,您可以在第二次保存尝试时对其进行操作。直接的方法是从数据库中查询最新值并相应地更新您的对象:

lock_version = Model.where(id: model.id).pluck(:lock_version).first
model.lock_version = lock_version

# then attempt to save again

model.save!

请注意,无论并行进行任何修改,这都会用您的更改重写数据库状态,从而违背了锁定的目的。

话虽如此,当更新超时时locking_version 的变化有点可疑。当然值得深入研究它,看看为什么会发生这种情况。至少您应该确保将更新包装在事务中,仅此一项就可以解决问题。

【讨论】:

    猜你喜欢
    • 2013-01-18
    • 1970-01-01
    • 1970-01-01
    • 2018-06-08
    • 1970-01-01
    • 1970-01-01
    • 2011-11-18
    • 2016-11-09
    • 2017-07-25
    相关资源
    最近更新 更多