Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
5
Help us understand the problem. What is going on with this article?
@yahagin

Railsで複数DB接続する

はじめに

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

5
Help us understand the problem. What is going on with this article?
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
yahagin
逃した魚はでかかった...

Comments

No comments
Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account Login
5
Help us understand the problem. What is going on with this article?