TL;DR:Registrering af serialiseringskonflikter blev dramatisk forbedret i Pg 9.1, så opgrader.
Det er svært at finde ud af din beskrivelse, hvad den faktiske SQL er, og hvorfor du forventer at få en tilbagerulning. Det ser ud til, at du alvorligt har misforstået serialiserbar isolation, måske tænker du, at den tester alle prædikater perfekt, hvilket den ikke gør, især ikke i side 8.4.
SERIALIZABLE
garanterer ikke perfekt, at transaktionerne udføres, som om de blev kørt i serie - da det ville være uoverkommeligt dyrt ud fra et præstationssynspunkt, hvis det overhovedet var muligt. Det giver kun begrænset kontrol. Præcis hvad der kontrolleres og hvordan varierer fra database til database og version til version, så du skal læse dokumenterne til din version af din database.
Anomalier er mulige, hvor to transaktioner udføres i SERIALIZABLE
mode giver et andet resultat, end hvis disse transaktioner virkelig udføres i serier.
Læs dokumentationen om transaktionsisolering på side for at lære mere. Bemærk, at SERIALIZABLE
ændret adfærd dramatisk i Pg 9.1, så sørg for at læse den version af manualen, der passer til din Pg-version. Her er 8.4-versionen
. Læs især 13.2.2.1. Serialiserbar isolation versus ægte serialiserbarhed
. Sammenlign nu det med den stærkt forbedrede prædikatlåsningsbaserede serialiseringsunderstøttelse beskrevet i Side 9.1 dokumenter
.
Det ser ud til, at du forsøger at udføre logik noget som denne pseudokode:
count = query("SELECT count(*) FROM the_table");
if (count < threshold):
query("INSERT INTO the_table (...) VALUES (...)");
Hvis det er tilfældet, vil det ikke fungere i Pg 8.4, når det udføres samtidigt - det er stort set det samme som det anomalieksempel, der er brugt i dokumentationen, der er linket til ovenfor. Utroligt nok virker det faktisk på side 9.1; Jeg forventede ikke, at selv 9.1's prædikatlåsning ville fange brugen af aggregater.
Du skriver at:
men 8.4 vil ikke opdage, at de to transaktioner er indbyrdes afhængige, noget du trivielt kan bevise ved at bruge to psql
sessioner for at teste det. Det er kun med de sand-serialiserbare ting, der blev introduceret i 9.1, at dette vil fungere - og ærligt talt var jeg overrasket over, at det virker i 9.1.
Hvis du vil gøre noget som at håndhæve et maksimalt antal rækker i side 8.4, skal du LOCK
bordet
for at forhindre samtidig INSERT
s, udfører låsningen enten manuelt eller via en triggerfunktion . At gøre det i en udløser vil i sagens natur kræve en låseforfremmelse og vil derfor ofte gå i dødvande, men vil med succes gøre jobbet. Det er bedre gjort i applikationen, hvor du kan udstede LOCK TABLE my_table IN EXCLUSIVE MODE
før du opnår endda SELECT
ing fra bordet, så den har allerede den højeste låsetilstand, den har brug for på bordet, og burde derfor ikke have brug for dødvande-tilbøjelig låsefremme. Den EXCLUSIVE
låsetilstand er passende, fordi den tillader SELECT
s men intet andet.
Sådan tester du det i to psql-sessioner:
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;
Når den køres på side 9.1, lykkes st commits succeeds then the second
COMMIT` mislykkes med:
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.
men når de køres på 8.4 lykkes begge commits commits, fordi 8.4 ikke havde al prædikatlåsekoden til serialiserbarhed tilføjet i 9.1.