我们有一个主数据库,我们所有的应用程序都驻留在其中。
但是还有第二个数据库(从外部源更新),我希望能够连接到它,以便从中提取数据。我不需要写任何东西......只是阅读。
它也只有一张我要从中拉出的桌子。
我真的只需要做类似的事情:
OtherDatabase.articles.where(id > 1000)
就是这样。
那么如何在 Rails(运行 3.2.13)中做到这一点?
我们有一个主数据库,我们所有的应用程序都驻留在其中。
但是还有第二个数据库(从外部源更新),我希望能够连接到它,以便从中提取数据。我不需要写任何东西......只是阅读。
它也只有一张我要从中拉出的桌子。
我真的只需要做类似的事情:
OtherDatabase.articles.where(id > 1000)
就是这样。
那么如何在 Rails(运行 3.2.13)中做到这一点?
对于简单的场景,Rails 可以支持这一点而无需任何额外的 gem;只需在 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")
=)
首先,我们需要定义外部数据库:
# 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
现在我们有了一个干净整洁的块,我们可以在任何我们喜欢的地方使用,在块内使用我们想要的任何模型,并且始终在外部数据库上运行。一旦该块完成,我们知道我们正在重新处理我们的原始数据库。
复制粘贴:
对于单主机情况,您可以在 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")