PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Rails, was der Unterschied zwischen eindeutigem Index und validates_uniqueness_of ist

Hier ist der Unterschied zwischen eindeutigem Index und validates_uniqueness_of

Dies ist ein Patch, der es ActiveRecord ermöglicht, von der Datenbank generierte Fehler für eindeutige Einschränkungsverletzungen zu identifizieren. Beispielsweise funktioniert Folgendes, ohne validates_uniqueness_of:

zu deklarieren
create_table "users" do |t|
  t.string   "email",   null: false
end
add_index "users", ["email"], unique: true

class User < ActiveRecord::Base
end

User.create!(email: '[email protected]')
u = User.create(email: '[email protected]')
u.errors[:email]
=> "has already been taken"

Die Vorteile sind Geschwindigkeit, Benutzerfreundlichkeit und Vollständigkeit --

Geschwindigkeit

Bei diesem Ansatz müssen Sie beim Speichern keine DB-Suche durchführen, um die Eindeutigkeit zu prüfen (was manchmal ziemlich langsam sein kann, wenn der Index übersehen wird -- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate.. . ). Wenn Sie sich wirklich für die Validierung der Eindeutigkeit interessieren, müssen Sie sowieso Datenbankeinschränkungen verwenden, damit die Datenbank die Eindeutigkeit in jedem Fall validiert, und dieser Ansatz entfernt eine zusätzliche Abfrage. Das zweimalige Überprüfen des Index ist kein Problem für die DB (es wird beim zweiten Mal zwischengespeichert), aber das Speichern eines DB-Roundtrips aus der Anwendung ist ein großer Gewinn.

Benutzerfreundlichkeit

Angesichts der Tatsache, dass Sie für echte Eindeutigkeit sowieso db-Einschränkungen haben müssen, lässt dieser Ansatz alles automatisch passieren, sobald die db-Einschränkungen vorhanden sind. Sie können immer noch validates_uniqueness_of verwenden, wenn Sie möchten.

Vollständigkeit

validates_uniqueness_of war schon immer ein kleiner Hack – es kann Rennbedingungen nicht richtig handhaben und führt zu Ausnahmen, die mit einer etwas redundanten Fehlerbehandlungslogik behandelt werden müssen. (Siehe Abschnitt „Parallelität und Integrität“ in http://api.rubyonrails .org/classes/ActiveRecord/Validations/ClassMe... )

validiert_eindeutigkeit_von reicht nicht aus, um die Eindeutigkeit eines Wertes sicherzustellen. Der Grund dafür ist, dass in der Produktion mehrere Worker-Prozesse Race Conditions verursachen können:

  1. Zwei gleichzeitige Anfragen versuchen, einen Benutzer mit demselben Namen zu erstellen (und wir möchten, dass Benutzernamen eindeutig sind)

  2. Die Anfragen werden auf dem Server von zwei Worker-Prozessen entgegengenommen, die sie nun parallel bearbeiten

  3. Beide Anfragen scannen die Benutzertabelle und sehen, dass der Name verfügbar ist

  4. Beide Anfragen bestehen die Validierung und erstellen einen Benutzer mit dem scheinbar verfügbaren Namen

Zum besseren Verständnis überprüfen Sie bitte dies

Wenn Sie einen eindeutigen Index für eine Spalte erstellen, bedeutet dies, dass die Tabelle garantiert nicht mehr als eine Zeile mit demselben Wert für diese Spalte enthält. Die Verwendung von nur validates_uniqueness_of-Validierung in Ihrem Modell reicht nicht aus, um die Eindeutigkeit zu erzwingen, da es gleichzeitig Benutzer geben kann, die versuchen, dieselben Daten zu erstellen.

Stellen Sie sich vor, dass zwei Benutzer versuchen, ein Konto mit derselben E-Mail-Adresse zu registrieren, bei der Sie validates_uniqueness_of :email in Ihrem Benutzermodell hinzugefügt haben. Wenn sie gleichzeitig auf die Schaltfläche „Anmelden“ klicken, sucht Rails in der Benutzertabelle nach dieser E-Mail und antwortet, dass alles in Ordnung ist und dass es in Ordnung ist, den Datensatz in der Tabelle zu speichern. Rails speichert dann die beiden Datensätze mit derselben E-Mail in der Benutzertabelle, und jetzt haben Sie ein wirklich beschissenes Problem zu lösen.

Um dies zu vermeiden, müssen Sie auch auf Datenbankebene eine eindeutige Einschränkung erstellen:

class CreateUsers < ActiveRecord::Migration
  def change
    create_table :users do |t|
      t.string :email
      ...
    end
    
    add_index :users, :email, unique: true
  end
end

Wenn Sie also den eindeutigen index_users_on_email-Index erstellen, erhalten Sie zwei sehr schöne Vorteile. Datenintegrität und gute Leistung, da eindeutige Indizes in der Regel sehr schnell sind.

Wenn Sie unique:true in Ihre Beitragstabelle für user_id eingeben, können Sie keine doppelten Datensätze mit derselben user_id eingeben.