2013-06-06 12 views
5

Stavo leggendo i diversi livelli di isolamento della transazione e ho rilevato il livello di isolamento SERIALIZABLE. So anche che database come Postgres, Oracle e MySQL supportano la sintassi SELECT .. FOR UPDATE.Transazioni serializzabili vs SELEZIONA PER AGGIORNAMENTO

Sono comunque confuso su come dovrebbero essere utilizzati quando desidero bloccare una riga (o un intervallo di righe) su cui desidero eseguire aggiornamenti.

Quando si utilizzava JPA in passato, ho sempre utilizzato @Transactional insieme a LockModeType.PESSIMISTIC_WRITE sulla query. Questo si traduce in un livello di isolamento READ_COMMITTED con un SELECT .. FOR UPDATE in SQL.

Ma ora, avendo letto SERIALIZABLE, mi chiedo cosa sarebbe diverso se usato @Transactional(isolation=SERIALIZABLE) con un normale SELECT (es em.findById recuperare un'entità indipendente), seguito da un UPDATE (unione della entità).

Il comportamento sarebbe lo stesso?

Ad esempio, ho un sistema di banca e desidero trasferire denaro tra due account. Ho bisogno di questi conti per non essere immischiati, mentre il trasferimento è in corso. Quindi, supponiamo di addebitare un account con -100 e accreditarlo nell'altro account. Quale sarebbe il modo migliore per garantire che questi account siano disponibili solo per la transazione che esegue l'aggiornamento?

Supponiamo che sto manipolando entità distaccate JPA, quindi prima dell'aggiornamento, dovrò leggerle dal DB, ad es. findById().

  • Usa @Transactional(isolation=READ_COMMITTED), em.findById con LockModeType.PESSIMISTIC_WRITE (vale a dire SELECT .. FOR UPDATE), e poi em.merge (vale a dire UPDATE)?
  • OPPURE Utilizzare @Transactional(isolation=SERIALIZABLE), em.findById, e quindi em.merge (cioè UPDATE)?

risposta

2

La differenza principale tra SERIALIZABLE e l'utilizzo di SELECT FOR UPDATE è che con SERIALIZABLE tutto è sempre bloccato. Dove, come per SELECT FOR UPDATE, si sceglie cosa e quando si blocca.

Quindi, se si desidera bloccare solo alcuni dati, ad esempio BankAccount ma non altri, ovvero Branch, AccountTypes, quindi SELECT FOR UPDATE offre un controllo molto migliore, dove SERIALIZABLE bloccherebbe l'intero sistema perché ogni transazione selezionata da ACCOUNT_TYPES tavolo. Inoltre, alcune transazioni potrebbero semplicemente voler controllare il saldo, quindi non è necessario bloccare la tabella ACCOUNT.

Sede,

http://en.wikibooks.org/wiki/Java_Persistence/Locking

+6

"* con SERIALIZABLE tutto è sempre bloccato *" non è vero come affermazione generale. Questo dipende fortemente dall'implementazione del DBMS (ad esempio Postgres non lo fa) –

+0

È vero che "PostgreSQL ad esempio non lo fa" in PostgreSQL serializzabile Effettua tutte le istruzioni di selezione senza Lock ma quando si verifica concorrenza alle istruzioni di scrittura l'ultima transazione ottiene fallito garantendo l'integrità serializzabile – deFreitas

0

Mi sembra che SERIALIZABLE non può lavorare in questa transazione commerciale, perché è necessario verificare alcune condizioni dopo aver selezionato un soggetto (ad esempio, se un account ha abbastanza i soldi). Le transazioni simultanee possono ottenere il valore sbagliato con il livello SERIALIZABLE, perché contiene il blocco condiviso (lettura) per SELECT.

Ma SELEZIONA ...FOR UPDATE funzionerà correttamente perché manterrà un blocco esclusivo fino alla fine di una transazione e costringerà altre transazioni ad attendere.