Poiché i deadlock si verificano così frequentemente, sembra che alcuni thread dell'applicazione contengano blocchi per un periodo di tempo prolungato.
Ogni thread nell'applicazione utilizzerà la propria connessione/connessioni al database durante l'accesso al database, quindi dal punto di vista del database due thread sono due client distinti che competono per i blocchi del database.
Se un thread mantiene i lock per un lungo periodo di tempo e li acquisisce in un certo ordine, e un secondo thread arriva acquisendo gli stessi lock ma in un ordine diverso, è inevitabile che si verifichi un deadlock (vedi qui per i dettagli su questa frequente causa di deadlock).
Si verificano anche deadlock nelle operazioni di lettura, il che significa che anche alcuni thread stanno acquisendo blocchi di lettura. Ciò accade se i thread eseguono transazioni in REPEATABLE_READ
livello di isolamento o SERIALIZABLE
.
Per risolvere questo problema, prova a cercare gli usi di Isolation.REPEATABLE_READ
e Isolation.SERIALIZABLE
nel progetto, per vedere se viene utilizzato.
In alternativa, usa il READ_COMMITTED
predefinito livello di isolamento e annota le entità con @Version
, per gestire la concorrenza utilizzando il blocco ottimistico
invece.
Prova anche a identificare le transazioni di lunga durata, questo accade a volte quando il @Transactional
viene posizionato nel posto sbagliato e racchiude, ad esempio, l'elaborazione di un intero file nell'esempio di un'elaborazione batch, invece di eseguire transazioni riga per riga.
Questa è una configurazione log4j per registrare la creazione/cancellazione di gestori di entità e le transazioni iniziano/commit/rollback:
<!-- spring entity manager and transactions -->
<logger name="org.springframework.orm.jpa" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
<logger name="org.springframework.transaction" additivity ="false">
<level value="debug" />
<appender-ref ref="ConsoleAppender" />
</logger >
- Posso eseguire in qualche modo una query di aggiornamento (JPA/nativa) senza dover bloccare la tabella tramite @Transactional?
Le query di aggiornamento sono possibili tramite query native o JPQL .
- Posso in qualche modo entrare in sessione senza usare @Transactional? Ad esempio, il thread pianificato tenta di leggere il campo Lazy su Entity restituisce LazyInitializationException - nessuna sessione, se il metodo non è annotato con @Transactional
In metodi senza @Transactional
, le query verranno eseguite nel proprio gestore di entità e restituiranno solo entità scollegate, poiché la sessione viene chiusa immediatamente dopo l'esecuzione della query.
quindi le eccezioni di inizializzazione pigra nei metodi senza @Transactional
è normale. Puoi impostarli su @Transactional(readOnly=true)
anche.