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.