sql >> Base de Datos >  >> RDS >> PostgreSQL

Nivel de aislamiento SERIALIZABLE en Spring-JDBC

TL;DR:la detección de conflictos de serialización mejoró drásticamente en Pg 9.1, así que actualice.

Es complicado averiguar a partir de su descripción cuál es el SQL real y por qué espera obtener una reversión. Parece que has malinterpretado seriamente el aislamiento serializable, tal vez pensando que prueba perfectamente todos los predicados, lo cual no es así, especialmente en Pg 8.4.

SERIALIZABLE no garantiza perfectamente que las transacciones se ejecuten como si se ejecutaran en serie, ya que hacerlo sería prohibitivamente costoso desde el punto de vista del rendimiento si fuera posible. Solo proporciona una verificación limitada. Exactamente lo que se verifica y cómo varía de una base de datos a otra y de una versión a otra, por lo que debe leer los documentos para su versión de su base de datos.

Las anomalías son posibles, donde dos transacciones se ejecutan en SERIALIZABLE modo producir un resultado diferente a si esas transacciones realmente se ejecutaran en serie.

Lea la documentación sobre el aislamiento de transacciones en Pg para obtener más información. Tenga en cuenta que SERIALIZABLE cambió drásticamente el comportamiento en Pg 9.1, así que asegúrese de leer la versión del manual apropiada para su versión de Pg. Esta es la versión 8.4 . En particular, lea 13.2.2.1. Aislamiento serializable versus Serializabilidad real . Ahora compare eso con el soporte de serialización basado en bloqueo predicado muy mejorado descrito en el Pág. 9.1 documentos .

Parece que estás tratando de realizar una lógica similar a este pseudocódigo:

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

Si es así, eso no funcionará en Pg 8.4 cuando se ejecute simultáneamente; es más o menos lo mismo que el ejemplo de anomalía utilizado en la documentación vinculada anteriormente. Sorprendentemente, en realidad funciona en la página 9.1; Ni siquiera esperaba que el bloqueo de predicados de 9.1 detectara el uso de agregados.

Escribes eso:

pero 8.4 no detectará que las dos transacciones son interdependientes, algo que puede probar trivialmente usando dos psql sesiones para probarlo. Solo funcionará con el material de serialización real introducido en 9.1 y, francamente, me sorprendió que funcione en 9.1.

Si desea hacer algo como imponer un número máximo de filas en Pg 8.4, debe LOCK la mesa para evitar INSERT concurrentes s, haciendo el bloqueo manualmente o a través de una función de activación . Hacerlo en un disparador requerirá inherentemente una promoción de bloqueo y, por lo tanto, con frecuencia se bloqueará, pero hará el trabajo con éxito. Es mejor hacerlo en la aplicación donde puedes emitir el LOCK TABLE my_table IN EXCLUSIVE MODE antes de obtener incluso SELECT ing de la mesa, por lo que ya tiene el modo de bloqueo más alto que necesitará en la mesa y, por lo tanto, no debería necesitar la promoción de bloqueo propenso a interbloqueos. El EXCLUSIVE el modo de bloqueo es apropiado porque permite SELECT s pero nada más.

He aquí cómo probarlo en dos sesiones de 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;

Cuando se ejecuta en Pg 9.1, el st commits succeeds then the second COMMIT` falla 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.

pero cuando se ejecuta en 8.4, ambas confirmaciones tienen éxito, porque 8.4 no tenía todo el código de bloqueo predicado para serialización agregado en 9.1.