sql >> Database >  >> RDS >> PostgreSQL

Isolatieniveau SERIALISEERBAAR in Spring-JDBC

TL;DR:Detectie van serialiseerbaarheidsconflicten is drastisch verbeterd in Pg 9.1, dus upgrade.

Het is lastig om uit uw beschrijving te achterhalen wat de eigenlijke SQL is en waarom u een terugdraaiing verwacht. Het lijkt erop dat je serialiseerbare isolatie ernstig verkeerd hebt begrepen, misschien omdat je denkt dat het alle predikaten perfect test, wat niet het geval is, vooral niet in Pg 8.4.

SERIALIZABLE garandeert niet perfect dat de transacties worden uitgevoerd alsof ze in serie worden uitgevoerd - omdat dit vanuit prestatieoogpunt onbetaalbaar zou zijn als het al mogelijk was. Het biedt slechts beperkte controle. Wat precies wordt gecontroleerd en hoe, verschilt van database tot database en van versie tot versie, dus u moet de documenten voor uw versie van uw database lezen.

Er zijn afwijkingen mogelijk, waarbij twee transacties worden uitgevoerd in SERIALIZABLE modus een ander resultaat opleveren dan wanneer die transacties echt in serie worden uitgevoerd.

Lees de documentatie over transactie-isolatie in Pg voor meer informatie. Merk op dat SERIALIZABLE veranderde het gedrag drastisch in Pg 9.1, dus zorg ervoor dat u de versie van de handleiding leest die geschikt is voor uw Pg-versie. Hier is de 8.4-versie . Lees in het bijzonder 13.2.2.1. Serializeerbare isolatie versus echte serialisatie . Vergelijk dat nu eens met de sterk verbeterde ondersteuning voor op predikaatvergrendeling gebaseerde serialisatie beschreven in de Pg 9.1 documenten .

Het lijkt erop dat je logica probeert uit te voeren zoals deze pseudocode:

count = query("SELECT count(*) FROM the_table");
if (count < threshold):
    query("INSERT INTO the_table (...) VALUES (...)");

Als dat zo is, zal dat niet werken in Pg 8.4 wanneer het gelijktijdig wordt uitgevoerd - het is vrijwel hetzelfde als het anomalie-voorbeeld dat wordt gebruikt in de documentatie waarnaar hierboven is gelinkt. Verbazingwekkend genoeg werkt het echt op pagina 9.1; Ik had niet verwacht dat zelfs de predikaatvergrendeling van 9.1 het gebruik van aggregaten zou opvangen.

Je schrijft dat:

maar 8.4 zal niet detecteren dat de twee transacties van elkaar afhankelijk zijn, iets wat je triviaal kunt bewijzen door twee psql te gebruiken sessies om het te testen. Het is alleen met de echte serialiseerbaarheid die in 9.1 is geïntroduceerd dat dit zal werken - en eerlijk gezegd was ik verrast dat het in 9.1 werkt.

Als je iets wilt doen als een maximum aantal rijen afdwingen in pagina 8.4, moet je LOCK de tafel om gelijktijdige INSERT te voorkomen s, het vergrendelen handmatig of via een triggerfunctie . Om het in een trigger te doen, is inherent een vergrendelingspromotie vereist en zal dus vaak vastlopen, maar zal het werk met succes doen. Het is beter gedaan in de applicatie waar je de LOCK TABLE my_table IN EXCLUSIVE MODE kunt uitgeven voordat je zelfs SELECT . verkrijgt van de tafel, dus het heeft al de hoogste vergrendelingsmodus die het op de tafel nodig heeft en heeft dus geen deadlock-gevoelige vergrendelingspromotie nodig. De EXCLUSIVE vergrendelmodus is geschikt omdat het SELECT . toestaat s maar niets anders.

Zo test je het in twee psql-sessies:

SESSION 1                               SESSION 2

create table ser_test( x text );

BEGIN TRANSACTION 
ISOLATION LEVEL SERIALIZABLE;


                                        BEGIN TRANSACTION 
                                        ISOLATION LEVEL SERIALIZABLE;

SELECT count(*) FROM ser_test ;

                                        SELECT count(*) FROM ser_test ;

INSERT INTO ser_test(x) VALUES ('bob');


                                        INSERT INTO ser_test(x) VALUES ('bob');

 COMMIT;

                                        COMMIT;

Wanneer uitgevoerd op pagina 9.1, slaagt de st commits succeeds then the second COMMIT` mislukt met:

regress=# COMMIT;
ERROR:  could not serialize access due to read/write dependencies among transactions
DETAIL:  Reason code: Canceled on identification as a pivot, during commit attempt.
HINT:  The transaction might succeed if retried.

maar wanneer uitgevoerd op 8.4 slagen beide commits, omdat 8.4 niet alle predikaatvergrendelingscodes voor serialiseerbaarheid had toegevoegd in 9.1.




  1. 1-1 Chatsysteem met PHP/MySQL

  2. Hoe voeg ik een JDBC-stuurprogramma toe aan een Jenkins-pijplijn?

  3. Sla UUID v4 op in MySQL

  4. MySQL-afrondingsfuncties