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

Blocco e transazione in postgres che dovrebbe bloccare una query

Il comportamento che descrivi è normale e previsto in qualsiasi database relazionale transazionale.

Se PostgreSQL ti ha mostrato il valore edited per il primo SELECT sarebbe sbagliato farlo - si chiama "lettura sporca" ed è una cattiva notizia nei database.

PostgreSQL può attendere al SELECT fino a quando non hai eseguito il commit o il rollback, ma non è richiesto dallo standard SQL, non gli hai detto che vuoi aspettare e non deve aspettare per alcun motivo tecnico, quindi restituisce i dati che hai chiesto per subito. Dopotutto, finché non viene eseguito il commit, quell'update esiste solo un tipo di esistenza:potrebbe ancora o non potrebbe accadere.

Se PostgreSQL avesse sempre aspettato qui, ti saresti rapidamente trovato in una situazione in cui solo una connessione alla volta potrebbe fare qualsiasi cosa con il database. Non è bello per le prestazioni e totalmente non necessario per la stragrande maggioranza del tempo.

Se vuoi attendere un UPDATE simultaneo (o DELETE ), useresti SELECT ... FOR SHARE . (Ma tieni presente che questo non funzionerà per INSERT ).

Dettagli:

SELECT senza un FOR UPDATE o FOR SHARE La clausola non accetta alcun blocco a livello di riga. Quindi vede qualunque sia la riga impegnata corrente e non è influenzata da alcuna transazione in corso che potrebbe modificare quella riga. I concetti sono spiegati nella sezione MVCC dei documenti . L'idea generale è che PostgreSQL sia copy-on-write, con il controllo delle versioni che gli consente di restituire la copia corretta in base a ciò che la transazione o l'istruzione potrebbe "vedere" al momento dell'avvio, ciò che PostgreSQL chiama "istantanea".

Nel predefinito READ COMMITTED gli snapshot di isolamento vengono presi a livello di istruzione, quindi se si SELECT una riga, COMMIT una modifica da un'altra transazione e SELECT di nuovo vedrai valori diversi anche all'interno di una transazione. Puoi usare SNAPSHOT isolamento se non vuoi vedere le modifiche salvate dopo l'inizio della transazione, o SERIALIZABLE isolamento per aggiungere ulteriore protezione contro determinati tipi di interdipendenze tra transazioni.

Vedi il capitolo sull'isolamento delle transazioni nella documentazione .

Se vuoi un SELECT per attendere che le transazioni in corso effettuino il commit o il rollback delle modifiche alle righe selezionate, è necessario utilizzare SELECT ... FOR SHARE . Questo bloccherà il blocco preso da un UPDATE o DELETE fino a quando la transazione che ha eseguito il blocco non esegue il rollback o il commit.

INSERT è diverso, però:le tuple semplicemente non esistono per altre transazioni fino al commit. L'unico modo per attendere INSERT simultanei s è prendere un EXCLUSIVE blocco a livello di tabella, quindi sai che nessun altro sta cambiando la tabella mentre la leggi. Di solito la necessità di farlo significa che hai un problema di progettazione nell'applicazione:la tua app non dovrebbe curare se sono presenti insert non vincolati è ancora in volo.

Vedi il capitolo sul blocco esplicito della documentazione .