PostgreSQL
 sql >> Baza danych >  >> RDS >> PostgreSQL

Railsy, ​​jaka jest różnica w unikalnym indeksie i validates_uniqueness_of

Oto różnica między unikalnym indeksem a validates_uniqueness_of

Jest to poprawka umożliwiająca ActiveRecord identyfikowanie błędów generowanych przez bazę danych w przypadku naruszeń unikatowych ograniczeń. Na przykład, wykonuje następującą pracę bez deklarowania validates_uniqueness_of:

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"

Korzyści to szybkość, łatwość użycia i kompletność --

Prędkość

Dzięki takiemu podejściu nie musisz wyszukiwać bazy danych, aby sprawdzić unikalność podczas zapisywania (co czasami może być dość powolne w przypadku pominięcia indeksu -- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate.. . ). Jeśli naprawdę zależy Ci na walidacji unikalności, i tak będziesz musiał użyć ograniczeń bazy danych, aby baza danych sprawdzała poprawność unikalności bez względu na wszystko, a to podejście usuwa dodatkowe zapytanie. Dwukrotne sprawdzenie indeksu nie stanowi problemu dla bazy danych (jest buforowana za drugim razem), ale zapisanie w obie strony bazy danych z aplikacji to wielka wygrana.

Łatwość użytkowania

Biorąc pod uwagę, że i tak musisz mieć ograniczenia bazy danych dla prawdziwej unikalności, to podejście pozwoli, aby wszystko stało się automatycznie po ustanowieniu ograniczeń bazy danych. Możesz nadal używać validates_uniqueness_of, jeśli chcesz.

Kompletność

validates_uniqueness_of zawsze był trochę hackiem — nie radzi sobie poprawnie z warunkami wyścigu i powoduje wyjątki, które muszą być obsługiwane przy użyciu nieco nadmiarowej logiki obsługi błędów. (Zobacz sekcję „Współbieżność i integralność” w http://api.rubyonrails .org/classes/ActiveRecord/Validations/ClassMe... )

validates_uniqueness_of nie wystarczy, aby zapewnić niepowtarzalność wartości. Powodem tego jest to, że w produkcji wiele procesów roboczych może powodować wyścigi:

  1. Dwa jednoczesne żądania próbują utworzyć użytkownika o tej samej nazwie (i chcemy, aby nazwy użytkowników były unikalne)

  2. Żądania są akceptowane na serwerze przez dwa procesy robocze, które będą teraz przetwarzać je równolegle

  3. Oba żądania skanują tabelę użytkowników i widzą, że nazwa jest dostępna

  4. Oba żądania przechodzą weryfikację i tworzą użytkownika o pozornie dostępnej nazwie

Aby uzyskać lepsze zrozumienie, sprawdź to

Jeśli utworzysz unikalny indeks dla kolumny, oznacza to, że masz gwarancję, że tabela nie będzie miała więcej niż jednego wiersza o tej samej wartości dla tej kolumny. Używanie tylko validates_uniqueness_of walidacji w swoim modelu nie wystarczy, aby wymusić unikalność, ponieważ mogą istnieć współbieżni użytkownicy próbujący utworzyć te same dane.

Wyobraź sobie, że dwóch użytkowników próbuje zarejestrować konto z tym samym adresem e-mail, do którego dodałeś validates_uniqueness_of :email w swoim modelu użytkownika. Jeśli w tym samym czasie nacisną przycisk „Zarejestruj się”, Railsy poszukają tego e-maila w tabeli użytkowników i odpowiedzą, że wszystko jest w porządku i że można zapisać rekord w tabeli. Railsy następnie zapiszą te dwa rekordy w tabeli użytkownika z tym samym e-mailem i teraz masz naprawdę gówniany problem do rozwiązania.

Aby tego uniknąć, musisz również utworzyć unikalne ograniczenie na poziomie bazy danych:

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

Tak więc tworząc unikalny indeks index_users_on_email otrzymujesz dwie bardzo miłe korzyści. Integralność danych i dobra wydajność, ponieważ unikalne indeksy są zwykle bardzo szybkie.

Jeśli umieścisz unique:true w tabeli postów dla identyfikatora użytkownika, nie pozwoli to na wprowadzenie zduplikowanych rekordów o tym samym identyfikatorze użytkownika.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. SET IDENTITY_INSERT postgresql

  2. java.lang.IllegalArgumentException:im ==null?

  3. TypeError:obiekt typu „DataFrame” nie jest możliwy do serializacji w formacie JSON

  4. Uzyskaj minimalną niezerową wartość w wielu kolumnach

  5. Jak wykonać kopię zapasową pojedynczej tabeli w bazie postgres?