Ab Rails 6.0 stehen standardmäßig mehrere Datenbanken zur Verfügung Die Verwendung mehrerer Datenbanken hat den Vorteil, dass die Skalierung bei wachsender Projektgröße vereinfacht und die Anzahl der Verbindungen erhöht wird.
In diesem Artikel werde ich versuchen, zwei Datenbanken und ein Replikat der Datenbank in einer Rails-Anwendung zu verwenden.
Der erstellte Quellcode wird auf GitHub veröffentlicht https://github.com/youichiro/rails-multiple-db-sandbox
Mehrere Datenbanken sind ein Mechanismus zum Lesen und Schreiben von Daten, indem von einer Anwendung aus eine Verbindung zu mehreren Datenbanken hergestellt wird. Wenn zwei DBs vorhanden sind, Datenbank A und Datenbank B, kann Rails ** die verbundene Datenbank entsprechend dem aufzurufenden Modell wechseln **
Es ist ein Mechanismus, um ein schreibgeschütztes Replikat für eine Datenbank vorzubereiten und je nach Anforderung zwischen Primär- und Replikat zu wechseln. Wenn die Anzahl der Zugriffe auf die Datenbank zunimmt, kann die Zugriffslast verteilt werden, indem die Datenbank zum Schreiben und die Datenbank zum Lesen getrennt werden. Rails schaltet ** POST-, PUT-, PATCH-, DELETE-Anforderungen automatisch auf primäre ** und ** GET, HEAD-Anforderungen für den Zugriff auf das Replikat ** um, wenn kein aktueller Schreibvorgang vorhanden ist.
Die config / database.yml
beim Erstellen einer solchen Datenbank sieht folgendermaßen aus:
config/database.yml
default: &default
adapter: mysql2
encoding: utf8mb4
pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
username: root
password:
host: localhost
port: 3306
development:
common:
<<: *default
database: rails_app_common_development
migrations_paths: db/common_migrate
common_replica:
<<: *default
database: rails_app_common_development
replica: true
school:
<<: *default
database: rails_app_school_development
migrations_paths: db/school_migrate
school_replica:
<<: *default
database: rails_app_school_development
replica: true
Für die Primärdatenbank gibt "migrations_paths" den Speicherort der Migrationsdatei an. Geben Sie "replica: true" für das Replikat an
Erstellen Sie mit dieser Einstellung eine Datenbank
$ bin/rails db:create
Wechseln Sie die verbundene Datenbank je nach aufzurufendem Modell Erstellen Sie eine abstrakte Klasse, die die Grundlage für das Modell bildet, das eine Verbindung zur gemeinsamen Datenbank herstellt, und beschreiben Sie die Einstellungen für die Verbindung zur Datenbank.
app/models/common_base.rb
class CommonBase < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :common, reading: :common_replica }
end
Erstellen Sie eine CommonBase-Klasse, die ApplicationRecord erbt, und geben Sie die Datenbank zum Zeitpunkt des Schreibens und die Datenbank zum Zeitpunkt des Lesens mit "connection_to" an.
Erstellen Sie eine abstrakte Klasse für das Modell, das auch eine Verbindung zur Schuldatenbank herstellt
app/models/school_base.rb
class SchoolBase < ApplicationRecord
self.abstract_class = true
connects_to database: { writing: :school, reading: :school_replica }
end
Stellen Sie sicher, dass Sie beim Erstellen eines neuen Modells entweder "CommonBase" oder "SchoolBase" erben Auf diese Weise können Sie das Datenbankverbindungsziel je nach Modell wechseln.
Dies ist das Verfahren zum Erstellen eines Benutzermodells in der gemeinsamen Datenbank. Erstellen Sie zunächst mit dem Befehl generate model eine Modelldatei und eine Migrationsdatei.
$ bin/rails g model user name:string school:references --database common
Running via Spring preloader in process 54763
invoke active_record
create db/common_migrate/20201030135726_create_users.rb
create app/models/user.rb
invoke test_unit
create test/models/user_test.rb
create test/fixtures/users.yml
Migrationsdatei im Verzeichnis "db / common_migrate" erstellt Durch Angabe der Datenbank, die eine Verbindung zu "--database" herstellen soll, wird diese in "migrations_paths" erstellt, die in database.yml festgelegt sind. Wenn Sie ein Modell in der Schuldatenbank erstellen möchten, geben Sie "--database school" an
Führen Sie dann die Migration durch
#Beim Anwenden aller Migrationsdateien
$ bin/rails db:migrate
#Wenn Sie nur die Migrationsdatei der gemeinsamen Datenbank anwenden
$ bin/rails db:migrate:common
Ändern Sie abschließend die Modelldatei Zum Zeitpunkt der Generierung erbt es ApplicationRecord. Da das Benutzermodell jedoch die gemeinsame Datenbank verwenden möchte, ändern Sie es in "CommonBase".
- class User < ApplicationRecord
+ class User < CommonBase
end
Jetzt können Sie aus der gemeinsamen Datenbank für das Benutzermodell lesen und schreiben.
Durch die Vorbereitung eines Replikats werden POST-, PUT-, DELETE-, PATCH-Anforderungen in die Primärdaten geschrieben, und GET, HEAD-Anforderungen werden aus dem Replikat gelesen. Um dies zu überprüfen, verwenden Sie arproxy, um den Datenbankverbindungsstatus im Abfrageprotokoll anzuzeigen.
config / initializers / arproxy.rb
config/initializers/arproxy.rb
if Rails.env.development? || Rails.env.test?
require 'multiple_database_connection_logger'
Arproxy.configure do |config|
config.adapter = 'mysql2'
config.use MultipleDatabaseConnectionLogger
end
Arproxy.enable!
end
lib / multiple_database_connection_logger.rb
lib/multiple_database_connection_logger.rb
class MultipleDatabaseConnectionLogger < Arproxy::Base
def execute(sql, name = nil)
role = ActiveRecord::Base.current_role
name = "#{name} [#{role}]"
super(sql, name)
end
end
Wenn Sie eine Anfrage von curl senden und sich das Protokoll ansehen, können Sie sehen, ob es geschrieben oder gelesen wurde Versuchen Sie es mit dem vorgefertigten users_controller.
index
$ curl localhost:3000/users
show
$ curl localhost:3000/users/1
create
$ curl -X POST -H 'Content-Type: application/json' -d '{"name": "saito", "school_id": 1}' localhost:3000/users
update
$ curl -X PUT -H 'Content-Type: application/json' -d '{"name": "saito(updated)"}' localhost:3000/users/5
destroy
$ curl -X DELETE http://localhost:3000/users/5
Im Fall von index, show action, wird gelesen, im Fall von create, update, destroy action wird geschrieben, und Sie können sehen, dass Primär / Replikat gewechselt ist.
Wenn Sie die Schülertabelle mit der Notentabelle verbinden, können Sie sich anschließen, da es sich um dieselbe Datenbank handelt
Grade.joins(:students).where(name: 'grade1')
SQL ausgegeben
SELECT `grades`.*
FROM `grades`
INNER JOIN `students` ON `students`.`grade_id` = `grades`.`id`
WHERE `grades`.`name` = 'grade1
Wenn Sie versuchen, die Schülertabelle mit der Benutzertabelle zu verbinden, können Sie nicht beitreten, da es sich um eine andere Datenbank handelt
User.joins(:students).where(name: 'ogawa')
Fehler, der auftritt
ActiveRecord::StatementInvalid (Mysql2::Error: Table 'rails_app_common_development.students' doesn't exist)
Wir freuen uns auf die Sharding-Funktionen, die von Rails 6.1 unterstützt werden
Recommended Posts