Esistono due approcci generali al blocco.
Innanzitutto, hai un blocco pessimistico. In questo approccio, blocchi la riga (SELECT ... FOR UPDATE
) che impedisce a chiunque altro di modificare la riga. Quindi fai il UPDATE
. Quando esegui il commit della modifica, il blocco viene rilasciato. In questo caso non è necessario avere una colonna numero di versione/marcatura temporale (almeno per non supportare il blocco) e il codice è relativamente semplice.
Lo svantaggio del blocco pessimistico è che è necessario mantenere il blocco per tutto il tempo in cui un utente è seduto su una pagina che potrebbe modificare i dati. Questo è tecnicamente molto difficile se stai creando un'applicazione basata sul Web poiché HTTP è un protocollo senza stato. La richiesta che inizialmente esegue il rendering della pagina otterrebbe normalmente una connessione dal pool di connessioni, eseguire SELECT
e quindi restituire la connessione al pool al termine della pagina. La successiva richiesta di aggiornamento dei dati avverrebbe generalmente su una connessione diversa con una sessione di database diversa, quindi non è possibile bloccare la riga nella prima sessione e aggiornarla nella seconda. Se si desidera bloccare pessimisticamente la riga, è necessario eseguire molto lavoro sul back-end per assicurarsi che l'unica connessione al database sia collegata a una particolare sessione di livello intermedio fino a quando l'utente non ha terminato la modifica dei dati. Questo in genere ha un impatto molto negativo sulla scalabilità e introduce tutti i tipi di problemi di gestione delle sessioni:come fai a sapere, ad esempio, se ho richiesto una pagina, bloccato una riga e quindi chiuso il browser senza mai disconnetterti o apportare modifiche? Per quanto tempo lascerai il record bloccato nel database? Cosa succede se un'altra sessione sta tentando di bloccare la riga? Per quanto tempo lascerai che quella sessione si blocchi in attesa di un blocco se la prima persona è uscita a pranzo? In genere, le persone non implementano il blocco pessimistico nelle app basate sul Web perché la gestione delle sessioni e dello stato delle sessioni è troppo poco pratica.
La seconda opzione è il blocco ottimistico. In questo approccio, aggiungi un numero di versione/un timestamp alla riga. Seleziona questo numero di versione/marcatura temporale quando esegui una query sui dati. Quindi lo usi nel tuo WHERE
clausola quando in seguito esegui l'aggiornamento e controlli quante righe sono state effettivamente modificate. Se modifichi esattamente una riga, sai che la riga non è cambiata da quando l'hai letta. Se modifichi 0 righe, sai che la riga è cambiata e puoi gestire l'errore.
Quindi, ad esempio, dovresti selezionare i dati insieme al numero di versione
SELECT address_line1, city, state, zip, version
FROM addressTable
WHERE address_id = `<<some key>>`
Quando eri pronto per eseguire l'aggiornamento, avresti fatto qualcosa di simile in cui utilizzavi la version
nel tuo UPDATE
e genera un errore se la riga è cambiata
UPDATE addressTable
SET address_line1 = `<<new address line 1>>`,
city = `<<new city>>`,
state = `<<new state>>`,
zip = `<<new zip>>`,
version = version + 1
WHERE address_id = `<<some key>>`
AND version = `<<version you read initially>>`
IF( SQL%ROWCOUNT = 0 )
THEN
-- Darn. The row must have changed since you read it. Do something to
-- alert the user. Most likely, the application will need to re-query the
-- data to see what the address has been changed to and then ask the user
-- whether they want to re-apply the changes.
RAISE_APPLICATION_ERROR( -20001, 'Oops, the row has changed since you read it.' );
END IF;
La tua applicazione farebbe quindi qualcosa di utile con l'errore. Normalmente, ciò significherebbe eseguire nuovamente una query sui dati, presentare le modifiche all'utente e chiedere loro se desiderano ancora applicare le modifiche. Se, ad esempio, leggo un indirizzo e inizio a modificarlo, vado a pranzo, il mio collega effettua il login, legge lo stesso indirizzo, apporta delle modifiche e lo salva, poi ritorno e provo a salvare le mie modifiche, in genere avrebbe senso per mostrarmi qualcosa che mi dice che il mio collega ha già cambiato l'indirizzo con qualcosa di nuovo:voglio continuare ad apportare modifiche o voglio abbandonarle.