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

apparente violazione dell'isolamento delle transazioni in postgresql

Sì e No - come al solito, dipende. La documentazione dice rigorosamente che:

In altre parole, semplicemente SELECT è diverso da SELECT FOR UPDATE/DELETE/UPDATE.

Puoi creare un semplice test case per osservare quel comportamento:

Sessione 1

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> DELETE FROM test;
DELETE 10
test=>

Ora accedi in un'altra Sessione 2:

test=> START TRANSACTION;
START TRANSACTION
test=> SELECT * FROM test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)


test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;

Dopo l'ultimo comando SELECT ... FOR UPDATE la sessione 1 "si blocca" ed è in attesa di qualcosa ......

Di nuovo nella sessione 1

test=> insert into test select * from generate_series(1,10);
INSERT 0 10
test=> commit;
COMMIT

E ora, quando torni alla sessione 2, vedrai questo:

test=> SELECT * FROM test WHERE x = 5 FOR UPDATE;
 x
---
(0 rows)


test=> select * from test;
 x
----
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
(10 rows)

Cioè - semplice SELECT continua a non vedere alcuna modifica, mentre SELECT ... FOR UPDATE vede che le righe sono state eliminate. Ma non vede nuove righe inserite dalla sessione 1

In effetti una sequenza che stai vedendo è:

  • Il processo A avvia la sua transazione
  • Il processo A elimina tutto dalla tabella T
  • il processo B avvia la sua transazione
  • Il processo B tenta una selezione per l'aggiornamento su una riga nella tabella T
  • Il processo B "si blocca" e attende fino a quando la sessione A non esegue un commit o un rollback
  • Il processo A ripopola la tabella T dai dati in entrata
  • Il processo A esegue il commit della sua transazione
  • Il processo B risulta vuoto (0 righe dopo il commit della sessione A) e chiama il rollback