Meerdere wijzigingen, één uitkomst · oefening
Laat de verbinding de uitkomst bepalen
De handmatige versie heeft twee takken en twee expliciete transactiebeslissingen. Een SQLite-verbinding kan diezelfde beslissingen nemen op basis van hoe een with-blok eindigt.
De vorm is van belang. Zet de verbindingscontext binnen de try en houd de verwachte handler erbuiten:
try:
with connection:
connection.execute(INSERT_LOAN, first_loan)
connection.execute(INSERT_LOAN, second_loan)
except sqlite3.IntegrityError:
return False
return True
Volg nu de twee manieren waarop dat blok kan eindigen. Het normale pad bereikt True pas nadat de context heeft gecommit. Op het pad met IntegrityError draait de context terug voordat de buitenste handler False teruggeeft:

Wanneer de uitvoering het einde van with connection: normaal bereikt, commit de verbinding het wachtende werk. Wanneer een exception het blok verlaat, draait de verbinding terug voordat de exception naar buiten doorgaat. De buitenste handler herkent daarna sqlite3.IntegrityError en geeft False terug. In de afbeelding is WITH CONNECTION het verbindingsblok, zijn INSERT 1 en INSERT 2 de twee invoegstappen en betekent BLOCK EXIT het verlaten van het blok. NORMAL EXIT leidt via COMMIT, het blijvend vastleggen, naar succes. INTEGRITY ERROR leidt via ROLLBACK, het terugdraaien, naar de handler buiten het blok.
Verwijder de handmatige aanroepen van commit() en rollback() tijdens deze refactor. Houd beide inserts binnen één context. Een context rond elke insert zou twee uitkomsten maken in plaats van één paar.
De handler mag niet naar binnen in with connection: verhuizen. Als die de integriteitsfout daar zou opvangen en normaal zou terugkeren, zou de context een normale afloop zien. Die zou de eerste geldige insert kunnen committen, waardoor het gedeeltelijke resultaat van het begin terugkomt.
Druk op Run. De zichtbare uitvoer blijft hetzelfde als bij je handmatige oplossing: geldige ID’s zijn na heropenen [7001, 7002], terwijl de poging met het ontbrekende lid False teruggeeft en op geen van beide verbindingen een voorgesteld ID achterlaat. Deze keer bereikte de verbinding die uitkomsten door het verlaten van de context.
Submit stuurt ook een losstaande fout door de functie en vereist dat die ontsnapt. Vang alleen het verwachte integriteitsgeval op. Het controleert de toestand via een nieuwe verbinding en voert nog een query uit via de oorspronkelijke verbinding.
Dit blok with connection: is een transactiecontext. Anders dan een bestandscontext betekent het niet “sluit dit object wanneer het blok eindigt.” Het bepaalt de uitkomst van de wachtende transactie. Voordat we meer bewerkingen toevoegen, maken we dat verschil in levensduur zichtbaar.
Opdracht
Refactor checkout_pair om één blok with connection: rond beide inserts te gebruiken. Zet de try om dat blok en vang alleen sqlite3.IntegrityError op nadat het is verlaten.
Verwijder handmatige commit- en rollbackaanroepen. Geef True terug na normale afronding en False bij de verwachte integriteitsfout.