PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Livello di isolamento SERIALIZZABILE in Spring-JDBC

TL;DR:il rilevamento dei conflitti di serializzabilità è notevolmente migliorato in Pg 9.1, quindi esegui l'upgrade.

È difficile capire dalla tua descrizione quale sia l'SQL effettivo e perché ti aspetti di ottenere un rollback. Sembra che tu abbia seriamente frainteso l'isolamento serializzabile, forse pensando che metta alla prova perfettamente tutti i predicati, cosa che non fa, specialmente non a Pg 8.4.

SERIALIZABLE non garantisce perfettamente che le transazioni vengano eseguite come se fossero eseguite in serie, in quanto ciò sarebbe proibitivo dal punto di vista delle prestazioni se fosse possibile. Fornisce solo un controllo limitato. Esattamente cosa viene controllato e come varia da database a database e da versione a versione, quindi devi leggere i documenti per la tua versione del tuo database.

Sono possibili anomalie, in cui due transazioni in esecuzione in SERIALIZABLE modalità producono un risultato diverso da se quelle transazioni eseguite veramente in serie.

Leggi la documentazione sull'isolamento delle transazioni in Pg per saperne di più. Nota che SERIALIZABLE ha cambiato drasticamente il comportamento in Pg 9.1, quindi assicurati di leggere la versione del manuale appropriata per la tua versione di Pg. Ecco la versione 8.4 . In particolare leggi 13.2.2.1. Isolamento serializzabile e vera serializzabilità . Ora confrontalo con il supporto per la serializzazione basato sul blocco dei predicati notevolmente migliorato descritto nel Pag. 9.1 documenti .

Sembra che tu stia cercando di eseguire una logica simile a questo pseudocodice:

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

In tal caso, non funzionerà in Pg 8.4 se eseguito contemporaneamente:è praticamente lo stesso dell'esempio di anomalia utilizzato nella documentazione collegata sopra. Sorprendentemente funziona effettivamente su Pg 9.1; Non mi aspettavo che nemmeno il blocco del predicato di 9.1 intercettasse l'uso degli aggregati.

Lo scrivi tu:

ma 8.4 non rileverà che le due transazioni sono interdipendenti, cosa che puoi provare banalmente usando due psql sessioni per testarlo. È solo con le funzionalità di serializzabilità reale introdotte nella versione 9.1 che funzionerà e, francamente, sono rimasto sorpreso che funzioni nella versione 9.1.

Se vuoi fare qualcosa come imporre un numero massimo di righe in Pg 8.4, devi LOCK il tavolo per evitare INSERT simultanei s, eseguendo il blocco manualmente o tramite una funzione trigger . Farlo in un trigger richiederà intrinsecamente una promozione del blocco e quindi spesso si verificherà un deadlock, ma eseguirà correttamente il lavoro. È meglio farlo nell'applicazione dove puoi emettere il LOCK TABLE my_table IN EXCLUSIVE MODE prima di ottenere anche SELECT ing dalla tabella, quindi ha già la modalità di blocco più alta di cui avrà bisogno sulla tabella e quindi non dovrebbe aver bisogno di una promozione di blocco soggetta a deadlock. L'EXCLUSIVE la modalità di blocco è appropriata perché consente SELECT s ma nient'altro.

Ecco come testarlo in due sessioni psql:

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;

Quando viene eseguito su Pg 9.1, il st commits succeeds then the second COMMIT` non riesce con:

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.

ma quando viene eseguito su 8.4 entrambi i commit hanno esito positivo, perché 8.4 non aveva tutto il codice di blocco del predicato per la serializzabilità aggiunto in 9.1.