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

AGGIORNAMENTO Atomico .. SELEZIONA in Postgres

Mentre il suggerimento di Erwin è forse il più semplice modo per ottenere un comportamento corretto (a condizione che tu riprovi la transazione se ottieni un'eccezione con SQLSTATE di 40001), le applicazioni di accodamento per loro natura tendono a funzionare meglio con il blocco delle richieste per avere la possibilità di fare il loro turno in coda rispetto all'implementazione PostgreSQL di SERIALIZABLE transazioni, che consente una maggiore concorrenza ed è un po' più "ottimista" sulle possibilità di collisione.

La query di esempio nella domanda, così com'è, nel valore predefinito READ COMMITTED il livello di isolamento della transazione consentirebbe a due (o più) connessioni simultanee di "rivendicare" la stessa riga dalla coda. Quello che accadrà è questo:

  • T1 inizia e arriva fino al blocco della riga in UPDATE fase.
  • T2 si sovrappone a T1 nel tempo di esecuzione e tenta di aggiornare quella riga. Si blocca in attesa del COMMIT o ROLLBACK di T1.
  • T1 esegue il commit, dopo aver "rivendicato" con successo la riga.
  • T2 prova ad aggiornare la riga, trova che T1 ha già, cerca la nuova versione della riga, trova che soddisfa ancora i criteri di selezione (che è proprio quell'id corrispondenze) e anche "rivendica" la riga.

Può essere modificato per funzionare correttamente (se stai usando una versione di PostgreSQL che consente il FOR UPDATE clausola in una sottoquery). Basta aggiungere FOR UPDATE alla fine della sottoquery che seleziona l'id, e questo accadrà:

  • T1 si avvia e ora blocca la riga prima di selezionare l'id.
  • T2 si sovrappone a T1 nel tempo di esecuzione e si blocca durante il tentativo di selezionare un id, in attesa del COMMIT o ROLLBACK di T1.
  • T1 esegue il commit, dopo aver "rivendicato" con successo la riga.
  • Quando T2 sarà in grado di leggere la riga per vedere l'id, vede che è stato rivendicato, quindi trova il successivo ID disponibile.

Alla REPEATABLE READ o SERIALIZABLE livello di isolamento della transazione, il conflitto di scrittura genererebbe un errore, che potresti rilevare e determinare un errore di serializzazione basato su SQLSTATE e riprovare.

Se in genere desideri transazioni SERIALIZZABILI ma desideri evitare nuovi tentativi nell'area di coda, potresti riuscire a farlo utilizzando un blocco di avviso.