Een manier om met impasses om te gaan, is door een mechanisme voor opnieuw proberen te gebruiken dat wacht op een willekeurig interval en probeert de transactie opnieuw uit te voeren. Het willekeurige interval is nodig zodat de botsende transacties niet continu tegen elkaar aan botsen, wat een zogenaamde live lock veroorzaakt - iets dat nog erger is om te debuggen. Eigenlijk hebben de meeste complexe applicaties vroeg of laat zo'n mechanisme voor opnieuw proberen nodig wanneer ze fouten in de serialisatie van transacties moeten afhandelen.
Als u de oorzaak van de impasse kunt achterhalen, is het natuurlijk veel beter om deze te elimineren, anders zal kom terug om je te bijten. In bijna alle gevallen, zelfs wanneer de deadlock-conditie zeldzaam is, is het kleine beetje doorvoer en coderingsoverhead om de sloten in deterministische volgorde te krijgen of meer grofkorrelige sloten te krijgen de moeite waard om af en toe een grote latentie-hit en de plotselinge prestatie-cliff te voorkomen bij het schalen van gelijktijdigheid.
Wanneer u consequent twee INSERT-instructies krijgt die vastlopen, is dit hoogstwaarschijnlijk een uniek probleem met de index-insertvolgorde. Probeer bijvoorbeeld het volgende in twee psql-opdrachtvensters:
Thread A | Thread B
BEGIN; | BEGIN;
| INSERT uniq=1;
INSERT uniq=2; |
| INSERT uniq=2;
| block waiting for thread A to commit or rollback, to
| see if this is an unique key error.
INSERT uniq=1; |
blocks waiting |
for thread B, |
DEADLOCK |
V
Gewoonlijk is de beste manier om dit op te lossen het achterhalen van de bovenliggende objecten die al dergelijke transacties bewaken. De meeste applicaties hebben een of twee primaire entiteiten, zoals gebruikers of accounts, die hiervoor goede kandidaten zijn. Dan is alles wat je nodig hebt voor elke transactie om de sloten te krijgen op de primaire entiteit die het aanraakt via SELECT ... VOOR UPDATE. Of als je er meerdere aanraakt, vergrendel ze dan allemaal, maar elke keer in dezelfde volgorde (bestellen op primaire sleutel is een goede keuze).