2015-04-14 3 views
19

Sto scrivendo una piccola app per l'asta ed è molto importante che le mie offerte vengano registrate con certezza. Dopotutto, gli ultimi due secondi dell'asta sono momenti critici per gli acquirenti, e non posso rischiare che si presentino simultaneamente e presentino una condizione di gara.Livelli di isolamento delle transazioni variabili su richiesta

E naturalmente, questo è l'isolamento delle transazioni. Posso impostare il mio livello di isolamento su serializzabile e siamo pronti.

Ma per quanto riguarda tutte le altre richieste? Se le persone stanno visualizzando i profili o inviando messaggi, queste richieste non sono necessarie in alcun modo vicino a questo tipo di isolamento della transazione. Un livello di isolamento impegnato in lettura è perfettamente accettabile per tali richieste.

Sto impostando il mio livello di transazione come parte della mia proprietà di ibernazione hibernate.connection.isolation, ma mi piacerebbe davvero essere in grado di fare qualcosa come session.setTransactionIsolation(newIsolation) per richiesta.

+0

Molto prudente con Serializable come livello di isolamento predefinito, poiché dovrai affrontare query row e table chiusura con serrature morte. Nella mia esperienza, i maggiori problemi con l'isolamento restrittivo riguarderanno il modello dei dati, il modo in cui l'ORM gestisce i recuperi e il modo in cui l'app apre e chiude le transazioni. – stringy05

+0

Le sezioni critiche dell'app (in particolare, le offerte) devono essere eseguite con atomicy e in modo serializzabile. Assolutamente no: non posso permettere a due persone di fare offerte sullo stesso articolo allo stesso prezzo, una di queste deve essere rifiutata. – corsiKa

+0

org.hibernate.Session session = (Session) entityManager.getDelegate(); Connessione connessione = session.connection(); connection.setTransactionIsolation (Connection.READ_UNCOMMITTED); ottenuto da http://stackoverflow.com/questions/2924147/jpa-and-mysql-transaction-isolation-level – StanislavL

risposta

3
Session session = getSession(dataSource, sessionFactory, Connection.TRANSACTION_SERIALIZABLE); 

public Session getSession(DataSource dataSource, SessionFactory sessionFactory, int isolationLevel){ 

    // Get connection from current dataSource and set new isolation 
    Connection connectionWithNewIsolation = dataSource.getConnection(); 
    connectionWithNewIsolation.setTransactionIsolation(isolationLevel); 

    // Get session from current sessionFactory with the new isolation 
    Session session = sessionFactory.openSession(connectionWithNewIsolation); 

    // Hibernate 4.3 
    //SessionFactory.openStatelessSession(Connection connection) 
    // Hibernate 3.6 
    //SessionFactory.openSession(Connection connection) 
    //SessionFactory.openStatelessSession(Connection connection) 

    return session; 
} 
+0

Questo 'getConnection' - crea una nuova connessione? Quindi ho bisogno di ripulire quella connessione quando ho finito? – corsiKa

+0

Sì, verrà stabilita una nuova connessione. session.close() pulirà la connessione per te. – jjcosare

+0

Questo sicuramente risponde esattamente a ciò che ho chiesto. Ma risulta che quello che ho chiesto non è quello che dovrei fare. Tuttavia, questo risponde alla domanda, che è esattamente quello che ho chiesto, giusto? =] – corsiKa

7

Se stai usando primavera si può usare qualcosa di simile:

@Transactional(isolation = Isolation.SERIALIZABLE) 

e it works for the JpaTransactionManager. Se si utilizza JtaTransactionManager, l'isolamento della transazione request-scope non viene propagato, poiché si tratta del comportamento JTA predefinito.

Poiché JTA non supporta i livelli di isolamento con ambito transazione, Spring offre lo IsolationLevelDataSourceRouter per ovviare a questo problema quando si utilizzano i DataSource JTA del server delle applicazioni.

Poiché la maggior parte delle implementazioni di DataSource può richiedere solo un livello di isolamento della transazione predefinito, è possibile avere più di tali origini dati, ognuna delle quali serve connessioni per uno specifico livello di isolamento della transazione.

L'impostazione del livello di isolamento della transazione logica (ad es. @Transactional) è introspected dallo IsolationLevelDataSourceRouter e la richiesta di acquisizione della connessione è quindi delegata a un'implementazione DataSource specifica che può servire una connessione JDBC con la stessa impostazione del livello di isolamento della transazione.

Quindi, anche in ambienti JTA, il router di isolamento della transazione può offrire una soluzione indipendente dal fornitore per sovrascrivere il livello di isolamento del database predefinito per transazione.

Java EE non supporta la configurazione di isolamento delle transazioni a livello di metodo.

Il livello di isolamento SERIALIZABLE protegge da letture non ripetibili e letture phantom e anche SERIALIZABLE non protegge l'utente against lost updates across multiple-request logical transactions.

Optimistic locking scale migliori quando si utilizzano le entità distaccate (poiché sono state caricate all'avvio della transazione logica).

+0

Alla ricerca di una risposta di ibernazione pura, non una direttamente legata a Spring. – corsiKa

+0

È correlato a DataSource, non qualcosa che Hibernate può controllare. Puoi fare ciò che la primavera fa per te, se sei disposto a fare da solo il routing. –

+0

Perché viene chiamato il livello di isolamento predefinito se non è possibile modificare l'impostazione predefinita al volo? Non è un'impostazione "predefinita", è un'impostazione permanente. Deve esserci un modo per cambiarlo (e, senza impostare una connessione per ogni livello di transazione, è un trucco ...) – corsiKa

2

Per questo caso, userò Optimistic lock in tue offerte oggetti ... la condizione di competizione sarà ancora accade, ma sarà rilevato quando la transazione prova per confermare le modifiche a portata di oggetti del dominio (un'eccezione se la versione letta è stata aggiornata da un altro thread).

Quindi qualsiasi modifica a qualsiasi oggetto di offerta, sarà quasi serializzabile (dico "quasi" perché per essere serializzabile, le transazioni fallite dovranno essere intercettate e riprovate in qualche modo).

+0

Quindi lasciate che tutti si scatenino perché il numero di collisioni sarà molto ridotto e quando si verificherà una collisione, riprovate semplicemente la richiesta? O nel mio caso particolare, dica all'utente "scusate, qualcuno ha offerto mentre stavate pensando - si prega di aggiornare" – corsiKa

+0

Esattamente ... tuttavia, io non se le collisioni saranno solo pochi ... potrebbe non essere, se ci sono molti utenti che fanno offerte contemporaneamente per un oggetto ricercato ... Potrebbe essere che dovresti eseguire dei test usando jmeter per vedere come questa strategia funziona per te ... –

+0

Questi sono i dettagli delle implementazioni ... dovrai analizzare quale strategia è un utente più amichevole ... la strategia del messaggio è facile da implementare, ma può causare frustrazione agli utenti che cercano di fare offerte molte volte senza successo (IMHO) .... –

0

se l'impostazione del livello di isolamento per transazione non riesce, è sempre possibile serializzare manualmente operazioni specifiche nel codice (sincronizzato, semafori, ecc.). tuttavia tieni a mente che non è scalabile (single jvm, operazione singola, facile da bypassare accidentalmente da altre parti del codice)

+0

È vero, ma questa deve essere necessariamente una soluzione scalabile (cloud). – corsiKa