Étant donné que les blocages se produisent si fréquemment, il semble que certains des threads de l'application maintiennent des verrous pendant une période prolongée.
Chaque thread de l'application utilisera sa ou ses propres connexions à la base de données lors de l'accès à la base de données, donc du point de vue de la base de données, deux threads sont deux clients distincts qui se disputent les verrous de la base de données.
Si un thread détient des verrous pendant une période de temps prolongée et les acquiert dans un certain ordre, et qu'un deuxième thread arrive à acquérir les mêmes verrous mais dans un ordre différent, un blocage est inévitable (voir ici pour plus de détails sur cette cause fréquente de blocage).
Des interblocages se produisent également dans les opérations de lecture, ce qui signifie que certains threads acquièrent également des verrous en lecture. Cela se produit si les threads exécutent des transactions dans REPEATABLE_READ
niveau d'isolement ou SERIALIZABLE
.
Pour résoudre ce problème, essayez de rechercher les utilisations de Isolation.REPEATABLE_READ
et Isolation.SERIALIZABLE
dans le projet, pour voir si cela est utilisé.
Comme alternative, utilisez le READ_COMMITTED
par défaut niveau d'isolement et annotez les entités avec @Version
, pour gérer la concurrence à l'aide du verrouillage optimiste
à la place.
Essayez également d'identifier les transactions de longue durée, cela se produit parfois lorsque le @Transactional
est placé au mauvais endroit et enveloppe par exemple le traitement d'un fichier entier dans l'exemple d'un traitement par lots, au lieu de faire des transactions ligne par ligne.
Il s'agit d'une configuration log4j pour enregistrer la création/suppression de gestionnaires d'entités et les transactions begin/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 >
- Puis-je d'une manière ou d'une autre exécuter une requête de mise à jour (JPA/Native) sans avoir à verrouiller la table via @Transactional ?
Les requêtes de mise à jour sont possibles via des requêtes natives ou JPQL .
- Puis-je accéder à une session d'une manière ou d'une autre sans utiliser @Transactional ? Par exemple, le thread planifié essaie de lire le champ Lazy sur l'entité donne lieu à LazyInitializationException - pas de session, si la méthode n'est pas annotée avec @Transactional
Dans les méthodes sans @Transactional
, les requêtes seront exécutées dans son propre gestionnaire d'entités et ne renverront que des entités détachées, car la session est fermée immédiatement après l'exécution de la requête.
donc les exceptions d'initialisation paresseuse dans les méthodes sans @Transactional
Est normal. Vous pouvez les définir sur @Transactional(readOnly=true)
aussi.