Ett sätt att hantera dödlägen är att ha en mekanism för att försöka igen som väntar på ett slumpmässigt intervall och försöker köra transaktionen igen. Det slumpmässiga intervallet är nödvändigt så att de kolliderande transaktionerna inte kontinuerligt stöter på varandra, vilket orsakar vad som kallas ett livelås - något som är ännu otäckare att felsöka. I själva verket kommer de flesta komplexa applikationer att behöva en sådan försöksmekanism förr eller senare när de behöver hantera transaktionsserialiseringsfel.
Om du kan fastställa orsaken till dödläget är det naturligtvis mycket bättre att eliminera det, annars kommer det att kom tillbaka för att bita dig. För nästan alla fall, även när dödlägestillståndet är sällsynt, är det lite av genomströmning och kodningsoverhead för att få låsen i deterministisk ordning eller få mer grovkorniga lås värt det för att undvika enstaka stora latensträffar och den plötsliga prestandaklippan vid skalning av samtidighet.
När du konsekvent får två INSERT-satser som låser sig är det troligtvis ett unikt problem med indexinfogningsordning. Prova till exempel följande i två psql-kommandofönster:
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
Vanligtvis är det bästa sättet att lösa detta att ta reda på de överordnade objekten som skyddar alla sådana transaktioner. De flesta applikationer har en eller två av primära enheter, såsom användare eller konton, som är goda kandidater för detta. Sedan behöver du bara för varje transaktion få låsen på den primära enhet den berör via VÄLJ ... FÖR UPPDATERING. Eller om du rör flera, skaffa lås på alla men i samma ordning varje gång (beställning efter primärnyckel är ett bra val).