Rails 中的多个数据库

Posted

技术标签:

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

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

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

【问题讨论】:

imnithin.github.io/multiple-database.html 【参考方案1】:

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

以下是一些参考资料:

ActiveRecord: Connection to multiple databases in different models Multiple Database Connections in Ruby on Rails Magic Multi-Connections

【讨论】:

再好不过了。例如,环境还使得在生产和开发之间拥有不同的数据库系统变得更加容易。我不建议这样做 我打算做一个类似的选择,因为我希望某些数据库表有数亿条记录。将数据库拆分为每个客户端的单独实例将允许我拥有具有多个数据库服务器的单个应用程序服务器。 您的最后两个链接不再相关。第一个可能会因新版本的 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 插件,它可以做一些事情:

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

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

【讨论】:

以上是关于Rails 中的多个数据库的主要内容,如果未能解决你的问题,请参考以下文章

Rails Transaction 更新多个数据库列

在 Rails 模型中使用多个 PostgreSQL 模式

你如何更改rails中的列数据类型?

使用 ActionMailer 在 Rails 中发送给多个收件人

访问和编辑rails中的相关数据

Rails 3 - 具有连接条件的多个数据库