Mysql
 sql >> Datenbank >  >> RDS >> Mysql

Hibernate:Beim Versuch, eine Sperre zu erhalten, wurde ein Deadlock gefunden

Da die Deadlocks so häufig auftreten, sieht es so aus, als würden einige Threads der Anwendung Sperren für einen längeren Zeitraum halten.

Jeder Thread in der Anwendung verwendet beim Zugriff auf die Datenbank seine eigene(n) Datenbankverbindung(en), sodass aus Sicht der Datenbank zwei Threads zwei unterschiedliche Clients sind, die um Datenbanksperren konkurrieren.

Wenn ein Thread über einen längeren Zeitraum Sperren hält und sie in einer bestimmten Reihenfolge erwirbt und ein zweiter Thread die gleichen Sperren erwirbt, aber in einer anderen Reihenfolge, kommt es unweigerlich zu einem Deadlock (siehe hier Einzelheiten zu dieser häufigen Deadlock-Ursache).

Außerdem treten bei Lesevorgängen Deadlocks auf, was bedeutet, dass einige Threads auch Lesesperren erwerben. Dies geschieht, wenn die Threads Transaktionen in REPEATABLE_READ ausführen Isolationsstufe oder SERIALIZABLE .

Versuchen Sie zur Lösung dieses Problems, nach Verwendungen von Isolation.REPEATABLE_READ zu suchen und Isolation.SERIALIZABLE im Projekt, um zu sehen, ob dies verwendet wird.

Verwenden Sie alternativ den Standardwert READ_COMMITTED Isolationsstufe und kommentieren Sie die Entitäten mit @Version , um Parallelität mit optimistischer Sperrung zu handhaben stattdessen.

Versuchen Sie auch, lang andauernde Transaktionen zu identifizieren, dies passiert manchmal, wenn @Transactional wird an der falschen Stelle platziert und wickelt beispielsweise die Verarbeitung einer ganzen Datei in das Beispiel einer Stapelverarbeitung ein, anstatt Transaktionen zeilenweise durchzuführen.

Dies ist eine log4j-Konfiguration zum Protokollieren der Erstellung/Löschung von Entitätsmanagern und Transaktionen 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 >
  1. Kann ich eine Aktualisierungsabfrage (entweder JPA/Native) irgendwie ausführen, ohne die Tabelle über @Transactional sperren zu müssen?

Aktualisierungsabfragen sind über native Abfragen oder JPQL möglich .

  1. Kann ich irgendwie in die Sitzung kommen, ohne @Transactional zu verwenden? Zum Beispiel versucht ein geplanter Thread, das Lazy-Feld auf der Entität zu lesen, ergibt eine LazyInitializationException - keine Sitzung, wenn die Methode nicht mit @Transactional annotiert ist

In Methoden ohne @Transactional , Abfragen werden in ihrem eigenen Entitätsmanager ausgeführt und geben nur getrennte Entitäten zurück, da die Sitzung unmittelbar nach Ausführung der Abfrage geschlossen wird.

also die faulen Initialisierungsausnahmen in Methoden ohne @Transactional ist normal. Sie können sie auf @Transactional(readOnly=true) setzen auch.