9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Railsで複数DB接続する

Last updated at Posted at 2019-07-26

はじめに

追記
ActiveRecord v6.0から組み込みで複数データベース接続機能が提供されたため、現在ここで紹介してライブラリ側から「ActiveRecord v6.1以降はサポートしません。」と明記されています。よほどの事情がない限り、ここで紹介しているライブラリではなく、ActiveRecord組込の複数DB接続機能を利用しましょう。
https://github.com/eagletmt/switch_point#maintenance-notice

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というメソッドもあるのですが、こちらは呼ばれると同時に、既存のコネクションを全部切断してしまうので、使用しませんでした。

9
6
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
6

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?