ActiveRecord单身危险吗?

时间:2014-01-24 15:00:19

标签: ruby-on-rails activerecord singleton

我写下面的代码。目的是避免使用活动记录查询我的数据库。

向数据库发出请求的唯一原因是更新(after_save)。

class Configuration < ActiveRecord::Base

  def self.instance
    ConfigurationSingleton.instance.active_record_instance
  end

  class ConfigurationSingleton
    include Singleton

    def initialize
      @active_record_instance = Configuration.first || Configuration.new
    end

    def active_record_instance
      @active_record_instance
    end
  end

  after_save Proc.new { ConfigurationSingleton.instance.active_record_instance.reload }
end

它似乎在开发模式下运作良好,但我觉得不安全。 这个代码是否可以安全地运行apache乘客进行生产并使用多个单独的流程?

2 个答案:

答案 0 :(得分:1)

如果您有几个不同的进程运行此代码,那么每个进程最终可能会出现“单例”。如果你有多个应用服务器,你肯定会遇到问题。

问题是将重新加载实例的唯一进程将是保存发生的进程。除非实例也保存在这些进程上,否则其他任何进程都不会知道它已更改。

所以:

  1. App server 1加载实例
  2. App server 2加载实例
  3. 应用服务器1上的实例更改
  4. App server 1重新加载实例
  5. 应用服务器2继续使用旧实例

答案 1 :(得分:0)

通过在列上放置唯一索引并在创建单例时将该列设置为固定值,可以轻松消除竞争条件的风险。只要确保在存在重复时处理SQL异常。

create_table :app_settings do |t|
  t.integer :unique, null: false, default: 1
  t.boolean :haz_mojo
end
add_index :app_settings, :unique, unique: true

另一个选择是,在创建单例后,选择id最低的行,而不是继续创建的引用。