Egentligen är det exakt så här kapslade transaktioner designades för. Jag citerar från oracle docs:
Alltså en underordnad transaktion i en vanlig kapslad transaktion har inget att säga till om hur han eller de andra barnen eller föräldern (större transaktion). ) kan fungera, annat än att ändra ömsesidig data eller misslyckas med ett undantag.
Men du kan bevilja honom (underordnad transaktion ) en mycket begränsad chans att rösta om sitt öde genom att använda sub-transaction
funktion som anges på rails dokument
genom att skicka requires_new: true
User.transaction do
User.create(username: 'Kotori')
User.transaction(requires_new: true) do
User.create(username: 'Nemu')
raise ActiveRecord::Rollback
end
end
Vilket som doktorerna säger:skapar bara 'Kotori'. sedan det mäktiga "Nemu"-barnet valde att dö tyst.
Mer information om inkapslade transaktionsregler (oracle docs )
Uppdatering:
För att bättre förstå varför rails nested transactions
fungerar på det här sättet, du behöver veta lite mer om hur kapslade transaktioner fungerar på DB-nivå, jag citerar från rails api-dokument
:
Ok, då beskriver dokumenten beteendet hos en nested transaction
i de två nämnda fallen enligt följande:
I händelse av ett kapslat anrop, #transaction kommer att bete sig enligt följande:
-
Blocket kommer att köras utan att göra något. Alla databassatser som sker inom blocket läggs effektivt till den redan öppna databastransaktionen.
-
Men om :requires_new är inställt kommer blocket att lindas in i en databassparpunkt som fungerar som en undertransaktion.
Jag föreställer mig försiktig, bara föreställ mig det:
alternativ(1) (utan requires_new) finns där om du använde ett DBMS som fullt ut stöder nested transactions
eller så är du nöjd med det "falska" beteendet hos nested_attributes
medan alternativ(2) är att stödja savepoint
lösning om du inte gör det.