sql >> Databáze >  >> RDS >> PostgreSQL

Úroveň izolace SERIALIZABLE v Spring-JDBC

TL;DR:Detekce konfliktů serializace se v Pg 9.1 dramaticky zlepšila, proto upgradujte.

Je složité z vašeho popisu zjistit, co je skutečný SQL a proč očekáváte vrácení zpět. Vypadá to, že jste vážně špatně pochopili serializovatelnou izolaci, možná si myslíte, že dokonale testuje všechny predikáty, což nedělá, zvláště ne v Pg 8.4.

SERIALIZABLE nezaručuje dokonale, že se transakce provádějí, jako by byly spuštěny v sérii – protože by to bylo z hlediska výkonu neúnosně drahé, pokud by to bylo vůbec možné. Poskytuje pouze omezenou kontrolu. Co přesně se kontroluje a jak se liší databáze od databáze a verze od verze, takže si musíte přečíst dokumenty pro svou verzi databáze.

Anomálie jsou možné, když se dvě transakce provádějí v SERIALIZABLE způsobí jiný výsledek, než kdyby byly tyto transakce skutečně provedeny v sérii.

Chcete-li se dozvědět více, přečtěte si dokumentaci o izolaci transakcí v Pg. Všimněte si, že SERIALIZABLE dramaticky změnilo chování v Pg 9.1, takže si přečtěte verzi příručky odpovídající vaší verzi Pg. Zde je verze 8.4 . Zejména si přečtěte 13.2.2.1. Serializovatelná izolace versus skutečná serializovatelnost . Nyní to porovnejte s výrazně vylepšenou podporou serializace založenou na predikátovém uzamčení popsanou v Dokumenty na str. 9.1 .

Vypadá to, že se pokoušíte provést logiku, něco jako tento pseudokód:

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

Pokud ano, nebude to fungovat v Pg 8.4 při souběžném spuštění - je to v podstatě stejné jako příklad anomálie použitý ve výše uvedené dokumentaci. Překvapivě to skutečně funguje na Pg 9.1; Nečekal jsem, že ani predikátové zamykání 9.1 zachytí použití agregátů.

Píšete, že:

ale 8.4 nezjistí, že tyto dvě transakce jsou na sobě závislé, což můžete triviálně dokázat pomocí dvou psql sezení, abyste to otestovali. To bude fungovat pouze se skutečnou serializovatelností zavedenou v 9.1 - a upřímně řečeno, byl jsem překvapen, že to funguje v 9.1.

Pokud chcete udělat něco jako vynucení maximálního počtu řádků v Pg 8.4, musíte LOCK stůl abyste zabránili souběžnému INSERT s, provedete zamykání buď ručně, nebo pomocí funkce spouštění . Pokud to uděláte ve spouštěči, bude ze své podstaty vyžadovat povýšení zámku, a proto se často zablokuje, ale svou práci úspěšně zvládne. Je lepší to udělat v aplikaci, kde můžete vydat LOCK TABLE my_table IN EXCLUSIVE MODE před získáním dokonce SELECT od stolu, takže již má nejvyšší režim uzamčení, který bude na stole potřebovat, a proto by neměl potřebovat propagaci zámku náchylného k uváznutí. EXCLUSIVE režim uzamčení je vhodný, protože umožňuje SELECT s ale nic jiného.

Zde je návod, jak to otestovat ve dvou psql relacích:

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;

Při spuštění na Pg 9.1 je st commits succeeds then the second COMMIT` se nezdaří s:

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.

ale při spuštění na 8.4 jsou obě revize úspěšné, protože 8.4 nemělo v 9.1 přidaný veškerý predikátový zamykací kód pro serializaci.




  1. MySQL group by a max vrací nesprávné řádky

  2. MYSQL vyberte počet podle hodnoty

  3. extrahovat datum z časového razítka v postgreSQL

  4. Vyberte všechna pole, kde hodnota pole není v poli