【问题标题】:Efficient way to pull data from second database?从第二个数据库中提取数据的有效方法?
【发布时间】:2013-05-08 03:45:12
【问题描述】:

我们有一个主数据库,我们的所有应用程序都驻留于此。

但是我希望能够连接到第二个数据库(从外部源更新),以便从中提取数据。我不需要写任何东西......只是阅读。

它也只有一张我要从中拉出的桌子。

我真的只需要这样做:

OtherDatabase.articles.where(id > 1000)

就是这样。

那么我该如何在 Rails(运行 3.2.13)中做到这一点?

【问题讨论】:

  • 请注意,如果您真的关心不写入现有数据库,则应使用仅被授予有限读取权限的凭据进行连接。即,不要依赖此应用程序的代码来强制执行其他应用程序的权限。

标签: ruby-on-rails database postgresql multiple-databases


【解决方案1】:

对于简单的场景,Rails 可以支持这一点而无需任何额外的宝石;只需在 database.yml 中定义数据库:

other_db:
  adapter: mysql2
  encoding: utf8
  database: other_db
  username: user
  password: passwd
  host: 1.2.3.4
  port: 3306

然后在你要使用其他数据库的模型中添加:

class Article < ActiveRecord::Base
  establish_connection(:other_db)
  self.table_name = 'other_db.articles'
end

然后你可以执行你的查询:

Article.where("id > 1000")

=)

【讨论】:

  • 在我得到它之后,我意识到两种方法的参数是不同的。您需要发送establish_connection(:other_db) 连接名称,这是database.yml 示例的第一行。但是self.table_name = 'other_db.articles'需要真正的数据库名称,即database.yml的第4行。
【解决方案2】:

首先,我们需要定义外部数据库:

# config/database.yml
external:
  adapter: sqlite3
  database: db/external.sqlite3
  pool: 5
  timeout: 5000

对于这样的事情,我更喜欢使用负责数据库连接的模块。

# lib/database.rb
module Database
  def self.using(db, klass=ActiveRecord::Base)
    klass.establish_connection(db.to_sym)
    result = yield if block_given?
    klass.establish_connection(Rails.env.to_sym)
    result
  end
end

通过将一个块传递给这样的模块,我们可以确保我们不会将查询流血到不属于它们的数据库中或忘记恢复我们的连接。此外,我们默认使用 ActiveRecord::Base 以便我们可以使用我们的任何模型。但是,如果我们知道我们只使用一个并且想要隔离我们的模型使用,我们可以将它作为辅助参数传递。

生成的实现可能如下所示:

# app/models/user.rb
class User < ActiveRecord::Base
  def read_remote
    Database.using(:external) do
      account = Account.where(active: true)
      account.users
    end
  end
end

现在我们有了一个干净整洁的块,我们可以在任何我们喜欢的地方使用,在块内使用我们想要的任何模型,并且始终在外部数据库上运行。一旦该块完成,我们就知道我们正在重新处理我们的原始数据库。

【讨论】:

  • 似乎有点矫枉过正,因为Account 总是连接到同一个数据库(在 OP 的情况下)。但它看起来像是一种将单个模型连接到多个数据库的有趣方法。
【解决方案3】:

复制/粘贴:

对于单主机情况,您可以在 database.yml 中为读取从机定义另一个数据库连接:

read_slave:
  adapter: postgresql
  database: read_only_production
  username: user
  password: pass
  host: read_slave_host

此数据库由一个模块支持,该模块使用此数据库连接镜像 ActiveRecord 类:

require 'magic_multi_connections'
module ReadSlave
  establish_connection :read_slave
end

现在,所有预先存在的模型都可以通过 read_slave 连接访问,方法是在模型类前面加上 ReadSlave::。

# use the read-only connection
    @user = ReadSlave::User.find(params[:id])

    # write to the master (can't use @user.update_attributes because it would#
    try to write to the read slave)
    User.update(@user.id, :login => "new_login")

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-05-29
    • 2013-08-18
    • 1970-01-01
    • 1970-01-01
    • 2019-01-07
    • 2018-12-24
    • 2021-11-18
    • 1970-01-01
    相关资源
    最近更新 更多