sabato 21 gennaio 2012

Optimistic Locking

Quando si realizzano applicazioni con un altro grado di concorrenzialità bisogna curare particolarmente gli aspetti relativi ai lock sul db.
In un sistema concorrenziale sono possibili 3 tipi di problemi:
  • Dirty Read : Un utente può leggere dati modificati e non ancora committati da altre transazioni, dati che quindi non è detto che debbano poi essere persistiti.
  • Nonrepeatable read : L'utente può leggere e modificare i dati non ancora committati, ad esempio l'entità USER prende l'entità ITEM, che è in gestione da parte di una transazione X che alla fine cancella ITEM. A questo punto USER ha ancora la copia dell'entità ITEM originale e può modificarla ma chiaramente andando a persistere il tutto su DB si incapperà in errori apparentemente inspiegabili;
  • Phantom read: accade quando l'utente nel corso della stessa transazione va a leggere per due volte un'entità e trova che la seconda volta i valori sono cambiati rispetto alla prima, poichè nel frattemo un'altra transazione ha modificato gli stessi
I livelli di isolamento tipicamente gestiti dai moderni DBMS sono i seguenti (ordinati dal piu basso livello di isolamento al più alto):

  • READ UNCOMMITTED: La transazione può leggere dati non committati di altre transazioni. Questo livello di isolamento porta inevitabilmente al rischio di DIRTY READ;
  • READ COMMITTED: La transazione può leggere soltanto dati committati, questo è il livello base per molti DBMS;
  • REPEATABLE READ: Con questo livello di isolamento si garantisce che nel corso della transazione qualora si acceda più volte allo stesso oggetto i valori restituiti saranno sempre gli stessi, per evitare il problema del Phantom Read;
  • SERIALIZABLE: E' il livello più alto di isolamento e garantisce che nessuna delle tabelle interessate dalla transazione sarà modificata da altri utenti. In questo modo chiaramente le performance dell'applicazione ne risentono molto.
Le strategie utilizzate per affrontare i problemi di concorrenzialità con gli EJB e JPA sono di 2 tipi:
  • Pessimistic Locking;
  • Optimistic Locking.
Il Pessimistic Locking parte dal presupposto che bisogna assolutamente impedire che si verifichino problemi di concorrenzialità per cui si lockano tutte le tabelle coinvolte nel database. JPA non provvede supporto per questa strategia, sebbene alcuni persistence provider abbiano estensioni proprietarie per gestirla.

L'Optimistic Locking invece è una strategia che parte dal presupposto che i problemi di concorrenzialità siano minimi e che sia quindi meglio risolverli quando accadono piuttosto che ingessare troppo il sistema.

L'implementazione dell'optimistic locking si basa sul fatto che quando un utente ottiene un oggetto dal db in realtà lavora su una copia dello stesso e poi al momento della persistenza dell'oggetto sul db il sistema rileva se nel frattempo quell'oggetto è stato modificato ed in tal caso torna un errore da gestire.
Per realizzare questa strategia si aggiungono alle tabelle interessate delle colonne di tipo version che possono essere interi o timestamp.

Vediamo un esempio:

@Entity
@Table("PERSONA")
public class Persona implements Serializable
@Id
@Column(name="ID_PERSONA")
protected long idPersona;
.......
@Version
@Column(name="VERSION")
private Long version;

......

Il campo version non può essere gestito dall'applicazione ma è modificato soltanto dal persistence provider.
Se all'atto dell'insert/update/delete dell'entità il sistema verifica un diverso valore del campo version torna all'utente una eccezione di tipo
javax.persistence.OptimisticLockException, una RuntimeException.

E' possibile con JPA anche gestire manualmente il lock, in questo modo:

entityManager.lock(object,LockModeType.READ)

Se si prova a chiamare il lock su un oggetto senza un campo annotato come Version il sistema torna una javax.persistence.PersistenceException (runtime Exception ed eccezione padre della OptimisticLockException).
LockModeType è un Enum che può assumere valori:
  • READ per ottenere un lock in lettura;
  • WRITE per impedire a chiunque altro di agire sull'entità, qualora altre transazioni accedessero otterrebbero una OptimisticLockException.


Nessun commento:

Posta un commento