Ok, da quanto hai appena risposto, deduco che qualcosa lo stai comprendendo. Ma forse è meglio se fornisco qualche spunto in più.
Se vai a leggere della documentazione sul
isolation level nelle transazioni su DB (anche banalmente su ), vedrai che ci sono 3 tipi di "anomalie" che possono avvenire. Sono denominate:
- Dirty reads
- Non-repeatable reads
- Phantom reads
Provo a farti un esempio ideato al volo di
dirty reads che è abbastanza semplice ma eloquente:
tempo
| ---start transazione A---
| INSERT INTO libri (.....
| ---start transazione B---
| SELECT * FROM libri
| INSERT INTO autori (..... ---end transazione B---
| INSERT INTO autori (.....
| ---end transazione A---
v
A livello di codice immagina di avere un LibriService con un metodo @Transactional
inserisciLibro(Libro) di questo tipo (abbozzato ma per dare l'idea):
@Transactional
public void inserisciLibro(Libro libro) {
libroDao.insert(libro);
for (Autore autore : libro.getAutori()) {
autoreDao.insert(autore);
}
}
E immagina che venga inserito un libro con 2 autori come mostrato nella transazione A. La domanda ora è:
la transazione B in cui legge TUTTI i libri, "vede" il libro inserito nella transazione A?? Nota che la SELECT è fatta poco dopo la prima INSERT e comunque prima della fine di transazione A.
Ora immagina che B "vede" il libro inserito. Potrebbe però capitare che la seconda INSERT dell'autore
fallisce. Per qualunque motivo possibile (vincolo violato, ecc...), non ha importanza ora
perché fallisce. Ma se fallisce, essendo in una transazione, deve avvenire un
rollback, quindi su database quel libro di fatto NON viene reso persistente e materialmente NON "esiste".
Ma la SELECT aveva visto e letto quel libro! Quindi se la query è fatta per presentare i libri all'utente, l'utente B vede nella sua pagina web un libro che NON esiste!! Bene, questo si chiama appunto un
dirty read, una lettura "sporca" dovuta al fatto che la transazione B ha "visto" dei dati
non ancora committati da un'altra transazione (la A) e che poi a causa del rollback sono spariti.
Il livello di isolamento chiamato
Read Uncommitted permette i
dirty reads mentre invece l'isolamento chiamato
Read Committed non li permette.
Nota che in PostgreSQL il Read Uncommitted non è gestito e, se settato, si comporta come Read Committed. Questo significa che perlomeno in PostgreSQL i dirty reads non sono mai possibili. Su altri database invece il Read Uncommitted è gestito e settabile.
Lo dice la documentazione
https://www.postgresql.org/docs/current/sql-set-transaction.html
The SQL standard defines one additional level, READ UNCOMMITTED. In PostgreSQL READ UNCOMMITTED is treated as READ COMMITTED.
Quindi devi conoscere queste 3 anomalie, Dirty reads/Non-repeatable reads/Phantom reads, e in base a cosa devi fare devi determinare se e come queste anomalie ti possono dare problemi. E di conseguenza settare l'isolation level o globalmente per ogni Connection oppure per-transaction.
L'isolamento "peggiore" è il Read Uncommitted mentre quello migliore e più consistente è il Serializable. Per garantire maggiore isolamento il database (quindi NON la tua applicazione) va ad utilizzare internamente una serie di
lock sulla riga o su range di righe o addirittura sulla intera tabella.
Quindi come ho già detto prima, NON è la invocazione del tuo metodo inserisciLibro() che si blocca e non ci entra dentro. Sono invece le singole query che ci possono mettere più tempo perché ci sono dei lock tenuti dal db a causa di un'altra transazione. Questo significa pertanto minore scalabilità e minore performance.