Ruby on Rails
ActiveRecord-transacties
Zoeken…
Opmerkingen
Transacties zijn beschermende blokken waarbij SQL-instructies alleen permanent zijn als ze allemaal als één atomaire actie kunnen slagen. Het klassieke voorbeeld is een overdracht tussen twee accounts waarbij u alleen een storting kunt doen als de opname is gelukt en vice versa. Transacties versterken de integriteit van de database en beschermen de gegevens tegen programmafouten of database-uitval. Dus in principe moet u transactieblokken gebruiken wanneer u een aantal overzichten hebt die samen moeten worden uitgevoerd of helemaal niet.
Basis voorbeeld
Bijvoorbeeld:
ActiveRecord::Base.transaction do
david.withdrawal(100)
mary.deposit(100)
end
Dit voorbeeld neemt alleen geld aan van David en geeft het aan Mary als noch opname noch storting een uitzondering oproept. Uitzonderingen dwingen een ROLLBACK af die de database terugzet naar de status voordat de transactie begon. Houd er echter rekening mee dat de instantiegegevens van de objecten niet worden hersteld.
Verschillende ActiveRecord-klassen in één transactie
Hoewel de transactieklasse methode wordt aangeroepen op een ActiveRecord-klasse, hoeven de objecten in het transactieblok niet alle exemplaren van die klasse te zijn. Dit komt omdat transacties per databaseverbinding zijn en niet per model.
In dit voorbeeld wordt een balansrecord per transactie opgeslagen, ook al wordt de transactie aangeroepen in de klasse Account:
Account.transaction do
balance.save!
account.save!
end
De transactiemethode is ook beschikbaar als modelinstellingsmethode. U kunt dit bijvoorbeeld ook doen:
balance.transaction do
balance.save!
account.save!
end
Meerdere database verbindingen
Een transactie werkt op een enkele databaseverbinding. Als u meerdere klassespecifieke databases hebt, beschermt de transactie de interactie daartussen niet. Een oplossing is om een transactie te starten voor elke klasse waarvan u de modellen wijzigt:
Student.transaction do
Course.transaction do
course.enroll(student)
student.units += course.units
end
end
Dit is een slechte oplossing, maar volledig gedistribueerde transacties vallen buiten het bereik van ActiveRecord.
opslaan en vernietigen worden automatisch verpakt in een transactie
Zowel #save als #destroy zijn verpakt in een transactie die ervoor zorgt dat alles wat u doet in validaties of callbacks gebeurt onder de beschermde dekking. U kunt dus validaties gebruiken om te controleren op waarden waarvan de transactie afhankelijk is of u kunt uitzonderingen in de callbacks tot rollback maken, inclusief after_*
callbacks.
Als gevolg hiervan worden wijzigingen in de database niet buiten uw verbinding gezien totdat de bewerking is voltooid. Als u bijvoorbeeld probeert de index van een zoekmachine bij te werken in after_save
de indexer het bijgewerkte record niet. De after_commit
callback is de enige die wordt geactiveerd zodra de update is after_commit
.
callbacks
Er zijn twee soorten callbacks verbonden aan het plegen en terugdraaien van transacties: after_commit
en after_rollback
.
after_commit
callbacks worden opgeroepen voor elk record dat is opgeslagen of vernietigd binnen een transactie onmiddellijk nadat de transactie is vastgelegd. after_rollback
callbacks worden op elk record opgeslagen of vernietigd binnen een transactie onmiddellijk nadat de transactie of het opslagpunt is teruggedraaid.
Deze callbacks zijn nuttig voor interactie met andere systemen, omdat u er zeker van kunt zijn dat de callback alleen wordt uitgevoerd wanneer de database permanent is. after_commit
is bijvoorbeeld een goede plek om het cachegeheugen te verwijderen, omdat het wissen vanuit een transactie ertoe kan leiden dat het cachegeheugen opnieuw wordt gegenereerd voordat de database wordt bijgewerkt.
Een transactie terugdraaien
ActiveRecord::Base.transaction
gebruikt de uitzondering ActiveRecord::Rollback
om opzettelijke rollback te onderscheiden van andere uitzonderlijke situaties. Normaal gesproken zorgt het verhogen van een uitzondering ervoor dat de .transaction
methode de database-transactie .transaction
en de uitzondering doorgeeft. Maar als u een ActiveRecord::Rollback
uitzondering ActiveRecord::Rollback
, wordt de database-transactie teruggedraaid, zonder de uitzondering door te geven.
U kunt dit bijvoorbeeld in uw controller doen om een transactie ongedaan te maken:
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