Dat is niet de schuld van PDO, het is inherent aan het transactiebeheer van PostgreSQL. Zie:
- Hoe kan ik PostgreSQL vertellen de hele transactie niet af te breken wanneer een enkele beperking is mislukt?
- Kan ik Postgresql vragen fouten in een transactie te negeren
- Terugdraaien na fout in transactie
PostgreSQL rolt de transactie niet terug, maar zet deze in een afgebroken staat waar het alleen terug kan draaien, en waar alle instructies behalve ROLLBACK
een fout melden:
(Het verbaast me dat hier niet naar wordt verwezen in de officiële documentatie; ik denk dat ik een patch moet schrijven om dat te verbeteren.)
Dus. Wanneer u de uitzondering in PDO probeert/vangt en inslikt, vangt u een uitzondering aan de PHP-zijde, maar u verandert niets aan het feit dat de PostgreSQL-transactie in een afgebroken staat is.
Als u uitzonderingen wilt kunnen slikken en de transactie wilt blijven gebruiken, moet u maak een SAVEPOINT
voor elke verklaring die zou kunnen mislukken. Als het niet lukt, moet je ROLLBACK TO SAVEPOINT ...;
. Als het lukt, mag je RELEASE SAVEPOINT ...;
. Dit legt extra overhead op de database voor transactiebeheer, voegt retouren toe en verbrandt transactie-ID's sneller (wat betekent dat PostgreSQL meer achtergrondopruimingswerk moet doen).
Het verdient over het algemeen de voorkeur om in plaats daarvan uw SQL te ontwerpen, zodat deze onder normale omstandigheden niet zal mislukken. U kunt bijvoorbeeld de meeste beperkingen aan de clientzijde valideren, waarbij u de beperkingen aan de serverzijde als een tweede zekerheidsniveau beschouwt terwijl de meeste fouten aan de clientzijde worden opgevangen.
Waar dat onpraktisch is, maakt u uw toepassing fouttolerant, zodat deze een mislukte transactie opnieuw kan proberen. Soms is dit hoe dan ook nodig - u kunt bijvoorbeeld over het algemeen geen savepoints gebruiken om te herstellen van deadlocks, afgebroken transacties of mislukte serialisatie. Het kan ook handig zijn om foutgevoelige transacties zo kort mogelijk te houden, waarbij u slechts het minimale werk doet dat nodig is, zodat u minder hoeft bij te houden en te herhalen.
Dus:Waar mogelijk, in plaats van een uitzondering te slikken, voert u foutgevoelige databasecode uit in een lus voor opnieuw proberen. Zorg ervoor dat uw code de informatie bijhoudt die nodig is om de hele transactie bij fout opnieuw te proberen, niet alleen de meest recente verklaring.
Onthoud, elke transactie kan mislukken:de DBA kan de database opnieuw opstarten om een patch toe te passen, het systeem kan geen RAM meer hebben vanwege een op hol geslagen cron-taak, enz. Fouttolerante apps zijn hoe dan ook een goed ontwerp.
Props voor jou dat je in ieder geval PDO-uitzonderingen gebruikt en uitzonderingen afhandelt - je loopt al ver voor op de meeste ontwikkelaars.