Sök…


Anmärkningar

Transaktioner är skyddande block där SQL-uttalanden endast är permanenta om de alla kan lyckas som en atomaktivitet. Det klassiska exemplet är en överföring mellan två konton där du bara kan ha en insättning om uttagningen lyckades och vice versa. Transaktioner säkerställer databasens integritet och skyddar data mot programfel eller databasfördelningar. Så i princip bör du använda transaktionsblock när du har ett antal uttalanden som måste köras tillsammans eller inte alls.

Grundläggande exempel

Till exempel:

ActiveRecord::Base.transaction do
  david.withdrawal(100)
  mary.deposit(100)
end

Detta exempel tar bara pengar från David och ger dem till Mary om varken uttag eller insättning ger ett undantag. Undantag kommer att tvinga fram en ROLLBACK som returnerar databasen till staten innan transaktionen inleddes. Var dock medveten om att objekten inte kommer att få sina instansdata tillbaka till deras pre-transaktionstillstånd.

Olika ActiveRecord-klasser i en enda transaktion

Även om transaktionsklassmetoden kallas för någon ActiveRecord-klass, behöver inte objekten inom transaktionsblocket alla vara instanser av den klassen. Detta beror på att transaktioner är per databasanslutning, inte per modell.

I det här exemplet sparas en balanspost transaktionsmässigt även om transaktion anropas i kontoklassen:

Account.transaction do
  balance.save!
  account.save!
end

Transaktionsmetoden finns också som en modellinstansmetod. Till exempel kan du också göra detta:

balance.transaction do
  balance.save!
  account.save!
end

Flera databasanslutningar

En transaktion verkar på en enda databasanslutning. Om du har flera klassspecifika databaser skyddar transaktionen inte interaktionen mellan dem. En lösning är att påbörja en transaktion på varje klass vars modeller du ändrar:

Student.transaction do
  Course.transaction do
    course.enroll(student)
    student.units += course.units
  end
end

Detta är en dålig lösning, men helt distribuerade transaktioner ligger utanför ActiveRecord.

spara och förstöra är automatiskt inslagna i en transaktion

Både #save och #destroy kommer inslagna i en transaktion som säkerställer att allt du gör i valideringar eller återuppringningar kommer att ske under dess skyddade skydd. Så du kan använda valideringar för att kontrollera om värden som transaktionen beror på eller så kan du höja undantag från återuppringningar till återuppringning, inklusive after_* återuppringningar.

Som en konsekvens ses inte ändringar i databasen utanför din anslutning förrän operationen är klar. Till exempel, om du försöker att uppdatera index för en sökmotor i after_save indexeraren inte ser uppdaterat register. after_commit återuppringning är den enda som utlöses när uppdateringen har genomförts.

callbacks

Det finns två typer av återuppringningar förknippade med att genomföra och rulla tillbaka transaktioner: after_commit och after_rollback .

after_commit återuppringningar kallas på varje post som sparats eller förstörts inom en transaktion omedelbart efter det att transaktionen har begåtts. after_rollback återuppringningar kallas på varje post som sparats eller förstörts inom en transaktion omedelbart efter det att transaktionen eller sparpunkten har rullats tillbaka.

Dessa återuppringningar är användbara för att interagera med andra system eftersom du garanteras att återuppringningen endast körs när databasen är i permanent tillstånd. Exempelvis är after_commit en bra plats att sätta i en krok för att rensa en cache eftersom rensning av den inom en transaktion kan leda till att cachen regenereras innan databasen uppdateras.

Rulla tillbaka en transaktion

ActiveRecord::Base.transaction använder ActiveRecord::Rollback undantaget för att skilja en avsiktlig rollback från andra exceptionella situationer. Normalt kommer en höjning av ett undantag att medföra .transaction att återuppta databastransaktionen och vidarebefordra undantaget. Men om du höjer ett ActiveRecord::Rollback undantag rullas databastransaktionen tillbaka utan att vidarebefordra undantaget.

Till exempel kan du göra detta i din controller för att återuppta en transaktion:

class BooksController < ActionController::Base
  def create
    Book.transaction do
      book = Book.new(params[:book])
      book.save!
      if today_is_friday?
        # The system must fail on Friday so that our support department
        # won't be out of job. We silently rollback this transaction
        # without telling the user.
        raise ActiveRecord::Rollback, "Call tech support!"
      end
    end
    # ActiveRecord::Rollback is the only exception that won't be passed on
    # by ActiveRecord::Base.transaction, so this line will still be reached
    # even on Friday.
    redirect_to root_url
  end
end


Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow