【问题标题】:Multiple databases in RailsRails 中的多个数据库
【发布时间】:2010-12-22 00:03:32
【问题描述】:

这可以吗?在单个应用程序中,它使用 SQLite 管理许多项目。 我想要的是为我的应用程序管理的每个项目都有一个不同的数据库.. 所以一个相同结构的数据库的多个副本,但其中包含不同的数据。我将根据 URI 上的参数选择要使用的副本。

这样做是为了 1. 安全性.. 我是这种编程的新手,我不希望在处理一个项目时由于某种原因另一个项目损坏.. 2. 轻松备份和旧项目的存档

【问题讨论】:

标签: ruby-on-rails database activerecord


【解决方案1】:

Rails 默认不是为多数据库架构设计的,在大多数情况下,它根本没有意义。 但是是的,您可以使用不同的数据库和连接。

以下是一些参考资料:

【讨论】:

  • 再好不过了。例如,环境还使得在生产和开发之间拥有不同的数据库系统变得更加容易。我不建议这样做
  • 我打算做一个类似的选择,因为我希望某些数据库表有数亿条记录。将数据库拆分为每个客户端的单独实例将允许我拥有具有多个数据库服务器的单个应用程序服务器。
  • 您的最后两个链接不再相关。第一个可能会因新版本的 Rails 而过时。请在答案中内联相关代码。
【解决方案2】:

如果您能够控制和配置每个 Rails 实例,并且由于它们处于待机状态而浪费资源,那么您可以省去一些麻烦,只需更改 database.yml 以修改每个实例上使用的数据库连接。如果您担心性能,这种方法将无法解决问题。

对于绑定到仅在一个数据库上的单个唯一表的模型,您可以在模型内部调用建立连接:

establish_connection "database_name_#{RAILS_ENV}"

如此处所述:http://apidock.com/rails/ActiveRecord/Base/establish_connection/class

您将有一些模型使用来自一个数据库的表,而其他不同的模型使用来自其他数据库的表。

如果您有相同的表,在不同的数据库上通用,并且由单个模型共享,ActiveRecord 将无法帮助您。早在 2009 年,我在一个正在使用 Rails 2.3.8 的项目中需要这个。我为每个客户建立了一个数据库,并用他们的 ID 命名了这些数据库。所以我创建了一个方法来改变 ApplicationController 内部的连接:

def change_database database_id = params[:company_id]
    return if database_id.blank?

    configuration = ActiveRecord::Base.connection.instance_eval { @config }.clone
    configuration[:database] = "database_name_#{database_id}_#{RAILS_ENV}"

    MultipleDatabaseModel.establish_connection configuration
end

并将该方法作为 before_filter 添加到所有控制器:

before_filter :change_database

所以对于每个控制器的每个动作,当 params[:company_id] 被定义和设置时,它会将数据库更改为正确的。

为了处理迁移,我扩展了 ActiveRecord::Migration,使用一种查找所有客户并使用每个 ID 迭代块的方法:

class ActiveRecord::Migration
    def self.using_databases *args
        configuration = ActiveRecord::Base.connection.instance_eval { @config }
        former_database = configuration[:database]

        companies = args.blank? ? Company.all : Company.find(args)

        companies.each do |company|
            configuration[:database] = "database_name_#{company[:id]}_#{RAILS_ENV}"
            ActiveRecord::Base.establish_connection configuration

            yield self
        end

        configuration[:database] = former_database
        ActiveRecord::Base.establish_connection configuration
    end
end

请注意,通过这样做,您将不可能在同一操作中从两个不同的数据库进行查询。您可以再次调用 change_database,但是当您尝试使用不再链接到正确数据库的对象执行查询的方法时,它会变得很糟糕。此外,很明显您将无法连接属于不同数据库的表。

为了正确处理这个问题,应该大大扩展 ActiveRecord。现在应该有一个插件可以帮助您解决这个问题。一项快速研究给了我这个:

DB-Charmer:http://kovyrin.github.com/db-charmer/

我愿意尝试。让我知道什么对你有用。

【讨论】:

    【解决方案3】:

    我通过使用其他数据库将它添加到我的模型顶部来解决这个问题

    class Customer < ActiveRecord::Base
      ENV["RAILS_ENV"] == "development" ? host = 'devhost' : host = 'prodhost'
    
      self.establish_connection(
          :adapter  => "mysql",
          :host     => "localhost",
          :username => "myuser",
          :password => "mypass",
          :database => "somedatabase"
        )
    

    【讨论】:

      【解决方案4】:

      您还应该看看这个名为 DB Charmer 的项目: http://kovyrin.net/2009/11/03/db-charmer-activerecord-connection-magic-plugin/

      DbCharmer 是一个简单但功能强大的 ActiveRecord 插件,它可以做一些事情:

      1. 让您轻松管理AR模型的连接(switch_connection_to方法)
      2. 允许您将 AR 模型的默认连接切换到单独的服务器/数据库
      3. 让您可以轻松选择查询的位置(on_* 方法系列)
      4. 允许您自动向从属设备发送读取查询,而主设备会处理所有更新。
      5. 将多个数据库迁移添加到 ActiveRecord

      【讨论】:

      • 插件已被作者杀死,截至2015年1月2日,无人介入维护。
      【解决方案5】:

      值得注意的是,在所有这些解决方案中,您需要记住关闭自定义数据库连接。您用完连接,否则会看到奇怪的请求超时问题。

      一个简单的解决方案是清除_active_connections!在控制器的 after_filter 中。

      after_filter :close_custom_db_connection
      
      def close_custom_db_connection
        MyModelWithACustomDBConnection.clear_active_connections!
      end
      

      【讨论】:

      • Rails 确实使用连接池,它应该防止过度使用某些连接限制。
      【解决方案6】:

      在你的 config/database.yml 中做这样的事情

      default: &default
        adapter: postgresql
        encoding: unicode
        pool: 5
      
      development:
        <<: *default
        database: mysite_development
      
      test:
        <<: *default
        database: mysite_test
      
      production:
        <<: *default
        host: 10.0.1.55
        database: mysite_production
        username: postgres_user
        password: <%= ENV['DATABASE_PASSWORD'] %>
      
      db2_development:
        <<: *default
        database: db2_development
      
      db2_test:
        <<: *default
        database: db2_test
      
      db2_production:
        <<: *default
        host: 10.0.1.55
        database: db2_production
        username: postgres_user
        password: <%= ENV['DATABASE_PASSWORD'] %>
      

      然后在您的模型中,您可以使用 db2 来引用

      class Customers < ActiveRecord::Base
        establish_connection "db2_#{Rails.env}".to_sym
      end
      

      【讨论】:

        【解决方案7】:

        您在问题中描述的是多租户(结构相同的数据库,每个数据库具有不同的数据)。 Apartment gem 非常适合这个。

        关于 Rails 中多数据库的一般问题:ActiveRecord 支持多数据库,但 Rails 没有提供管理它们的方法。我最近创建了Multiverse gem 来解决这个问题。

        【讨论】:

          【解决方案8】:

          目前我发现的最佳解决方案是:

          我们可以采用 3 种数据库架构。

          • 单个租户的单个数据库
          • 每个租户的单独架构
          • 租户共享架构

          注意:它们有一定的优缺点取决于您的用例。

          我从这个Blog 得到这个!对我很有帮助。

          您可以将 gem Apartment 用于 rails

          您可以在Gorails for apartment关注视频参考

          【讨论】:

            【解决方案9】:

            从 Rails 6 开始,支持多个数据库:https://guides.rubyonrails.org/active_record_multiple_databases.html#generators-and-migrations

            对于迟到且显而易见的答案感到抱歉,但认为它是可行的,因为它现在受到支持。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-01-08
              • 1970-01-01
              • 1970-01-01
              • 2023-03-06
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多