Hibernate: Deadlock gefunden, wenn versucht wird, eine Sperre zu erhalten

8

Ich benutze Hibernate in meinem Projekt und ich bekomme zufällig scheinbare Deadlocks für sehr einfache Datenbankoperationen.

Es gibt einen der Stack-Traces: Ссылка - Was mich verwirrt, ist, dass die erste Ausnahme RollbackException ist und dann dort sind LockAquisition Ausnahmen.

Das Problem tritt oft bei ähnlichen Klauseln auf:

%Vor%

Ich bin ziemlich fest, wie ich nicht weiß, ob es Problem von Hibernate, MySQL oder C3P0 ist.

Meine Hibernate-Konfiguration:

%Vor%

EDIT1:

  • Ich habe oben geschrieben, dass es scheinbare Deadlocks gab - das war falsch, nur "Deadlock gefunden, wenn versucht wurde, ein Schloss zu bekommen" passiert.

EDIT2:

Dies geschieht auch bei diesen Methoden - die NEEDS müssen mit @Transactional:

versehen werden %Vor%     
Vojtěch 14.02.2014, 10:45
quelle

2 Antworten

19

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

Jeder Thread in der Anwendung verwendet seine eigene Datenbankverbindung / -verbindungen beim Zugriff auf die Datenbank. Aus der Sicht der Datenbank sind also zwei Threads zwei verschiedene Clients, die um Datenbanksperren konkurrieren.

Wenn ein Thread Sperren für einen längeren Zeitraum hält und sie in einer bestimmten Reihenfolge erwirbt und ein zweiter Thread die gleichen Sperren erwirbt, aber in einer anderen Reihenfolge, muss ein Deadlock auftreten (siehe hier für Details zu dieser häufigen Deadlock-Ursache).

Auch Deadlocks treten bei Leseoperationen auf, was bedeutet, dass einige Threads auch Lesesperren erhalten. Dies geschieht, wenn die Threads Transaktionen in REPEATABLE_READ isolation level oder SERIALIZABLE ausführen.

Um dies zu beheben, suchen Sie im Projekt nach Verwendungen von Isolation.REPEATABLE_READ und Isolation.SERIALIZABLE , um festzustellen, ob diese verwendet werden.

Alternativ können Sie die Standard-Isolationsstufe READ_COMMITTED verwenden und die Entitäten mit @Version annotieren, um die Parallelität mit optimistische Sperrung statt.

Versuchen Sie auch, Transaktionen mit langer Laufzeit zu identifizieren. Dies geschieht manchmal, wenn @Transactional an der falschen Stelle platziert wird und beispielsweise die Verarbeitung einer ganzen Datei im Beispiel einer Stapelverarbeitung umgeht, anstatt Transaktionen zeilenweise auszuführen .

Dies ist eine log4j-Konfiguration, um das Erstellen / Löschen von Entity Managern und Transaktionen zu protokollieren. Begin / Commit / Rollback:

%Vor%
  1. Kann ich die Aktualisierungsabfrage irgendwie ausführen (entweder JPA / Native), ohne die Tabelle über @Transactional sperren zu müssen?

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

  1. Kann ich irgendwie in Sitzung gelangen, ohne @Transactional zu verwenden? Beispiel: geplanter Thread versucht Lazy-Feld auf Entität zu LazyInitializationException - keine Sitzung zu lesen, wenn die Methode nicht mit @Transactional

In Methoden ohne @Transactional werden Abfragen im eigenen Entitätsmanager ausgeführt und geben nur getrennte Entitäten zurück, da die Sitzung sofort geschlossen wird, nachdem die Abfrage ausgeführt wurde.

Die normalen Initialisierungsausnahmen in Methoden ohne @Transactional sind also normal. Sie können sie auch auf @Transactional(readOnly=true) setzen.

    
Angular University 18.02.2014, 23:26
quelle
3

Dies ist der Fehler bei MySQL.

Der einfachste Weg, um & amp; Vermeiden Sie Deadlocks, um die DB-Vorgänge in der Anwendung neu zu ordnen.

Deadlock tritt meistens auf, wenn mehr als eine Ressource / Verbindung versucht, mehr als eine Sperre bei entgegengesetzten Befehlen zu erhalten, wie unten:

%Vor%

In dem Szenario, in dem beide Verbindungen gleichzeitig ausgeführt werden, erhält Verbindung 1 die Sperre für Schlüssel (1) und Verbindung 2 für Schlüssel (2). Danach warten beide Verbindungen auf die Freigabe der Sperre für den Schlüssel. Dies führt zu einem Deadlock.

Aber, ein kleiner Tweak in der Reihenfolge der Transaktionen, dann können Deadlocks vermieden werden.

%Vor%

Die obige Reihenfolge ist Deadlock-sicher.

Andere Möglichkeiten zur Vermeidung von Deadlocks bestehen in einem Transaktionsverwaltungsmechanismus. Transaktionsverwaltung von Spring ist fast plug-n-play. Darüber hinaus können Sie eine Deadlock-Wiederholungsrichtlinie einrichten. Eine interessante Deadlock-Wiederholung über Spring AOP findet sich hier . Auf diese Weise müssen Sie die Annotation nur der Methode hinzufügen, die im Fall eines Deadlocks erneut versucht werden soll.

Wenn Sie mehr Debug-Protokolle für Deadlocks haben, um herauszufinden, welche Anweisungen verdächtig sind, versuchen Sie, die Diagnose "show engine innodb status" auszuführen. Außerdem können Sie Wie man mit Deadlocks umgehen .

UPDATE: Ein Szenario für Deadlocks in transaktionalen DB-Operationen.

In einer Transaktionsdatenbank tritt ein Deadlock auf, wenn zwei Prozesse innerhalb einer eigenen Transaktion zwei Informationszeilen aktualisieren, jedoch in umgekehrter Reihenfolge. Beispiel: Prozess A aktualisiert Zeile 1 und Zeile 2 im exakten Zeitrahmenprozess. B aktualisiert Zeile 2 und dann Zeile 1. Prozess A kann die Aktualisierung der Zeile 2 nicht abschließen, bis Prozess B beendet ist. Die Aktualisierung von Zeile 1 kann jedoch erst abgeschlossen werden Ein Ende. Unabhängig davon, wie viel Zeit verstreichen darf, wird sich diese Situation niemals selbst lösen, und aus diesem Grund werden Datenbankmanagementsysteme typischerweise die Transaktion des Prozesses beenden, der am wenigsten Arbeit geleistet hat.

Shishir

    
Shishir Kumar 17.02.2014 09:45
quelle

Tags und Links