sql >> Database teknologi >  >> RDS >> PostgreSQL

Rails hvad der er forskellen i unikt indeks og validates_uniqueness_of

Her er forskellen mellem unikt indeks og validates_uniqueness_of

Dette er en patch, der gør det muligt for ActiveRecord at identificere db-genererede fejl for unikke overtrædelser af begrænsninger. For eksempel får det følgende til at fungere uden at erklære en 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"

Fordelene er hastighed, brugervenlighed og fuldstændighed --

Hastighed

Med denne tilgang behøver du ikke lave et db-opslag for at kontrollere, om der er unikhed, når du gemmer (hvilket nogle gange kan være ret langsom, når indekset overses -- https://rails.lighthouseapp.com/projects/8994/tickets/2503-validate.. . ). Hvis du virkelig bekymrer dig om at validere unikhed, bliver du alligevel nødt til at bruge databasebegrænsninger, så databasen vil validere unikhed uanset hvad, og denne tilgang fjerner en ekstra forespørgsel. At tjekke indekset to gange er ikke et problem for DB (det cachelagres anden gang), men at gemme en DB-rundtur fra applikationen er en stor gevinst.

Brugervenlighed

Da du alligevel skal have db-begrænsninger for ægte unikhed, vil denne tilgang lade alt bare ske automatisk, når først db-begrænsningerne er på plads. Du kan stadig bruge validates_uniqueness_of, hvis du vil.

Fuldstændighed

validates_uniqueness_of har altid været lidt af et hack -- det kan ikke håndtere løbsforhold ordentligt og resulterer i undtagelser, der skal håndteres ved hjælp af noget redundant fejlhåndteringslogik. (Se afsnittet "Samtidighed og integritet" i http://api.rubyonrails .org/classes/ActiveRecord/Validations/ClassMe... )

validerer_uniqueness_of er ikke tilstrækkeligt til at sikre en værdis unikke karakter. Årsagen til dette er, at i produktionen kan flere arbejdsprocesser forårsage raceforhold:

  1. To samtidige anmodninger forsøger at oprette en bruger med samme navn (og vi ønsker, at brugernavne skal være unikke)

  2. Anmodningerne accepteres på serveren af ​​to arbejdsprocesser, som nu vil behandle dem parallelt

  3. Begge anmodninger scanner brugertabellen og ser, at navnet er tilgængeligt

  4. Begge anmodninger består validering og opretter en bruger med det tilsyneladende tilgængelige navn

For mere klar forståelse, tjek venligst dette

Hvis du opretter et unikt indeks for en kolonne, betyder det, at du er garanteret, at tabellen ikke vil have mere end én række med samme værdi for den kolonne. At kun bruge validates_uniqueness_of validation i din model er ikke nok til at håndhæve unikhed, fordi der kan være samtidige brugere, der forsøger at oprette de samme data.

Forestil dig, at to brugere forsøger at registrere en konto med den samme e-mail, hvor du har tilføjet validates_uniqueness_of :e-mail i din brugermodel. Hvis de trykker på knappen "Tilmeld" på samme tid, vil Rails kigge i brugertabellen efter den e-mail og svare tilbage, at alt er i orden, og at det er ok at gemme posten i tabellen. Rails vil derefter gemme de to poster i brugertabellen med den samme e-mail, og nu har du et rigtig lorte problem at håndtere.

For at undgå dette skal du også oprette en unik begrænsning på databaseniveau:

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

Så ved at oprette det unikke index_users_on_email-indeks får du to meget gode fordele. Dataintegritet og god ydeevne, fordi unikke indekser har tendens til at være meget hurtige.

Hvis du angiver unik:sand i din posttabel for user_id, vil det ikke tillade at indtaste duplikerede poster med samme user_id.



  1. Hvordan ignorerer man SequelizeUniqueConstraintError i Sequelize?

  2. Mysql øger automatisk en kolonne med én specifik primærnøgle

  3. Min SQL Konvertering til Int, når den ikke burde O.o

  4. PostgreSQL - kunne ikke identificere en lighedsoperator for typen json