Di solito, la soluzione a tali problemi di concorrenza prevede transazioni e blocco ottimistico :quando aggiorni il contatore, aggiungi un where
clausola per verificare il vecchio valore e contare il numero di righe aggiornate.
v = select value from counter where id=x.
update counter set value = v+1 where value = v and id=x
Se il contatore è stato aggiornato nel frattempo, l'aggiornamento non cambierà alcuna riga, quindi sai che devi eseguire il rollback e provare ancora una volta la transazione.
Un problema è che potrebbe portare a un'elevata contesa , con solo poche transazioni che vanno a buon fine e molte che falliscono.
Allora potrebbe essere meglio attenersi al blocco pessimistico , dove prima blocchi la riga, quindi la aggiorni. Ma solo un benchmark te lo dirà.
MODIFICA
Se si utilizza la transazione senza il blocco ottimistico, potrebbe verificarsi lo scenario seguente.
Max authorized = 50. Current value = 49.
T1: start tx, read value --> 49
T2: start tx, read value --> 49
T1: update value --> 50, acquire a row lock
T1: commits --> release the lock
T2: update value --> 50, acquire a row lock
T2: commits --> release the lock
Entrambe le transazioni hanno esito positivo, il valore è 50, ma c'è un'incoerenza.