Verwenden Sie mit Rails 6.0 mehrere Datenbanken

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

Was ich getan habe

Mehrere Datenbanken

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 ** スクリーンショット 2020-10-31 4.17.26.png

Primär- / Replikatdatenbank

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.

スクリーンショット 2020-10-31 14.17.32.png

Datenbankeinstellungen

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

Erstellen Sie eine abstrakte Klasse für das Modell

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.

Modell erstellen

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.

Überprüfen Sie, ob Primär / Replikat auf Anfrage gewechselt wird

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.

Arproxy-Einstellungen

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


class MultipleDatabaseConnectionLogger < Arproxy::Base
 def execute(sql, name = nil)
  role = ActiveRecord::Base.current_role
  name = "#{name} [#{role}]"
  super(sql, name)
 end
end

Überprüfen Sie den Datenbankverbindungsstatus zum Zeitpunkt der Anforderung

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

スクリーンショット 2020-10-31 18.40.58.png

show

$ curl localhost:3000/users/1

スクリーンショット 2020-10-31 18.41.09.png

create

$ curl -X POST -H 'Content-Type: application/json' -d '{"name": "saito", "school_id": 1}' localhost:3000/users

スクリーンショット 2020-10-31 18.47.08.png

update

$ curl -X PUT -H 'Content-Type: application/json' -d '{"name": "saito(updated)"}' localhost:3000/users/5

スクリーンショット 2020-10-31 18.48.18.png

destroy

$ curl -X DELETE http://localhost:3000/users/5

スクリーンショット 2020-10-31 18.48.41.png

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.

Überprüfen Sie das Verhalten von JOIN

Sie können zwischen Tabellen in derselben Datenbank beitreten

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

JOIN kann nicht zwischen Tabellen in verschiedenen Datenbanken ausgeführt werden

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)

schließlich

Wir freuen uns auf die Sharding-Funktionen, die von Rails 6.1 unterstützt werden

Referenz

Recommended Posts

Verwenden Sie mit Rails 6.0 mehrere Datenbanken
Verwenden Sie mehrere Kontrollkästchen in Rails6!
[Docker] Wird immer mit Docker + Rails verwendet
[Rails] Verwenden Sie jQuery
Laden Sie einfach mehrere Bilder mit Rails Rails + Carrierwave + Cloudinary hoch
[Rails] Verfahren zum Verknüpfen von Datenbanken mit Ruby On Rails
Einfaches Diagramm mit Rails ausgeben Verwenden Sie gem-chartkick / groupdate
[Ruby on Rails] Hochladen mehrerer Bilder mit Refile
Verwenden Sie ProGuard mit Gradle
[Rails 6] Laufzeitfehler mit $ Rails s
Verwenden Sie Puphpeteer mit Docker
Verwenden Sie XVim2 mit Xcode 12.0.1
Verwenden von CentOS mit LXD
Gerät mit Schienen handhaben
[Rails] Lernen mit Rails Tutorial
[Schienen] Test mit RSpec
Verwenden Sie Webmock mit Rspec
Verwenden Sie Bilder mit Schienen
[Rails] Entwicklung mit MySQL
Verwenden Sie WebJars mit Gradle
Unterstützt Mehrsprachigkeit mit Rails!
Verwenden Sie jlink mit gradle
Verwenden Sie Lambda-Ebenen mit Java
Verwenden Sie GDAL mit Python mit Docker
Warum kann ich den mit gem installierten Befehl Rails verwenden? ??
Verwenden Sie Thymeleaf mit Azure-Funktionen
[Rails] Polymorph mit graphql-rubin ausdrücken
[Rails] Videos mit Rails hochladen (ActiveStorage)
[Vue Rails] "Hallo Vue!" Wird mit Vue + Rails angezeigt
[RSpec] Verwenden wir FactoryBot [Rails]
[Rails] Verwendung von Enum
Japanisieren Sie mit i18n mit Rails
Verwenden Sie die Bulk-API mit RestHighLevelClient
Vorbereitung für die Entwicklung mit Rails
Verwenden Sie SDKMAN! Mit Git Bash
Verwendung von Rails Join
Führen Sie Rails immer im Docker aus
[Docker] Rails 5.2-Umgebungskonstruktion mit Docker
[Rails] Geben Sie das Format mit link_to an
[Rails] Verwendung der Validierung
Verwenden Sie Spring JDBC mit Spring Boot
[Rails] Suche aus mehreren Spalten + Bedingungen mit Gem und Ransack
[Rails] So verwenden Sie authenticate_user!
Verwenden Sie Ruby mit Google Colab
Verwenden Sie SpatiaLite mit Java / JDBC
Verwenden Sie log4j2 mit YAML + Gradle
Verwenden Sie mit Rails6 Ihre eigene Klasse im lib-Verzeichnis
[Schienen] Verwendung von Scope
Verwenden Sie PlantUML mit Visual Studio Code
[Rails] Wie man Edelstein "devise" benutzt