Help us understand the problem. What is going on with this article?

Railsで複数DB接続する

はじめに

Rails5では、複数DB接続が公式ではサポートされていません(Rails6からは公式サポートされるそうです)。
しかし、読み込み系の処理はリードレプリカに、書き込み系の処理はmasterにって処理を振り分けたいという需要があったので、その時にやったことの備忘録として投稿します。

Modelを介す場合

SwitchPointを使用しました。

Switch Pointの設定

Gemfile
gem 'switch_point'

database.yml
production:
  # 省略

production_slave:
  # 省略
config/initializers/switch_point.rb
SwitchPoint.configure do |config|
  config.auto_writable = true
  database_config = {
    readonly: :"#{Rails.env}_slave",
    writable: :"#{Rails.env}"
  }
  config.define_switch_point :setting, database_config
end
SwitchPoint::writable!(:setting)

SwitchPoint::writable!(:setting)
と書いておくことでデフォルトの接続先がmasterを向きます。

使い方

Slaveに向ける

hoge.rb
Hogemodel.with_readonly do
  data = Hogemodel.where(id: 1)
end

Hogemodel.with_readonly do
  aaa = Hogemodel.where(id: 1)
  aaa.title = 'フロントエンドのプロ直伝! CSS余白設定の三原則(+線の引き方)'
  Hogemodel. with_writable do
    aaa.save!
  end
end

Slaveから読み込んでMasterに書き込む

hoge.rb
Hogemodel.with_readonly do
  aaa = Hogemodel.where(id: 1)
  aaa.title = 'フロントエンドのプロ直伝! CSS余白設定の三原則(+線の引き方)'
  Hogemodel.with_writable do
    aaa.save!
  end
end

Slaveに対して生SQLを発行したい場合

ときにはORMでは表現しにくい複雑なクエリをslaveに対して発行したいときもあると思います。

slave_db.rb
module SlaveDb
  extend ActiveSupport::Concern
  class << self

    # slaveDBとコネクションを確立するための情報を返す
    def get_slave_db_connection
      db_config = Rails.configuration.database_configuration
      db_env = "#{Rails.env}_slave"
      ActiveRecord::Base.mysql2_connection(
        adapter: db_config[db_env]['adapter'],
        host: db_config[db_env]['host'],
        username: db_config[db_env]['username'],
        password: db_config[db_env]['password'],
        database: db_config[db_env]['database']
      )
    end
  end
end

Rails(MySQLに限る)は新しくDBとのコネクションを呼ぶ際に、内部的にmysql2_connectionというメソッドを叩いているため、database.ymlから取得した、slaveへの接続先を渡してこのメソッドを叩きます。

サクッと使いまわせるように、今回はconcernに処理を書きました。
呼び出し側では、

slave_db.rb
include SlaveDb
begin
  # きっと複雑なクエリ
  query <<-"EOL"
    select * from ...
  EOL
  con = SlaveDb.get_slave_db_connection
  data_list = con.select_all(query).to_hash
ensure
  con&.disconnect!
end

こんな感じで使えます。

似たようなメソッドにestablish_connectionというメソッドもあるのですが、こちらは呼ばれると同時に、既存のコネクションを全部切断してしまうので、使用しませんでした。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away