7 Stimmen

Spring synchronisiert Hibernate- und JMS-Transaktionen

Ich arbeite an einer eigenständigen Anwendung, die sowohl JMS als auch Hibernate verwendet.

Die Dokumentation legt nahe, dass JTA verwendet werden muss, wenn ich Transaktionen über beide Ressourcen hinweg haben möchte.

Mit einer @Transaction annotierten DAO-Methode (und HibernateTransactionManager) scheint dies jedoch bereits zu funktionieren. Wenn ich send() auf dem JmsTemplate aufrufe, wird die Nachricht nicht sofort gesendet, sondern die JMS-Sitzung wird mit der Hibernate-Sitzung verbunden, wenn die Methode zurückkehrt.

Ich wusste nicht, wie das ohne den JtaTransactionManager möglich ist, also habe ich mir den Quellcode angesehen. Es stellte sich heraus, dass sowohl der Wrapper für Hibernate als auch JmsTemplate die Sitzungen beim TransactionSynchronizationManager registriert und die JMS-Sitzung beim Commit der Hibernate-Sitzung übertragen wird.

Was ist der Unterschied zwischen dieser und einer JTA-Transaktion? Kann ich letztere durch diese ersetzen?

16voto

Brad Punkte 14476

Kurz gesagt: Nein, ohne JTATransactionManager und XA-fähige Datenquellen gibt es keine Unterstützung für 2-Phasen-Commit.

Sie sind Zeuge einer Koordinierung von zwei Lokale Transaktionen nur 1-Phasen-Übertragung unterstützt. Die grobe Durchführung dieser Abfolge von Ereignissen...

  1. JMS-Transaktion starten
  2. JMS-Nachricht lesen
  3. JDBC-Transaktion starten
  4. Schreiben in die Datenbank
  5. JDBC-Transaktion festschreiben
  6. JMS festschreiben/bestätigen

Die JMS-Transaktion wird zuerst gestartet und umschließt die verschachtelte JDBC-Transaktion, so dass die JMS-Warteschlange ein Rollback durchführt, wenn die Hibernate/JDBC-Übertragung fehlschlägt. Ihr JMS-Listener-Container sollte wie folgt eingerichtet sein nicht zu acknowledge="auto" und warten stattdessen, bis die Hibernate-Transaktion abgeschlossen ist, bevor sie die Bestätigung senden.

Wenn Sie nur diese beiden Ressourcen haben, dann ist das Problem, das Sie berücksichtigen müssen, wenn Hibernate erfolgreich persistiert, dann erhalten Sie eine Exception, bevor Sie den JMS-Server bestätigen können. Das ist kein großes Problem, da die JMS-Nachricht nicht verloren geht und Sie sie wieder lesen können.

Allerdings

  1. Sie müssen Ihren MessageListener so schreiben, dass er doppelte Nachrichten vom Server verarbeitet

  2. Sie müssen auch mit einer Nachricht umgehen, die aufgrund von fehlerhaften Daten nicht verarbeitet werden kann und in einer Endlosschleife endet, in der versucht wird, sie zu verarbeiten. In diesem Fall kann der Server so konfiguriert sein, dass er die Nachricht in eine "tote Nachrichtenwarteschlange" verschiebt, oder Sie kümmern sich selbst darum in dem MessageListener

Andere Optionen und weiterführende Literatur

Wenn Ihr JMS-Server keine (globalen) XA-Transaktionen unterstützt, ist dies so ziemlich Ihre einzige Lösung.

Wenn der JMS-Server XA-Transaktionen unterstützt, JDBC aber nicht, können Sie einen JTATransactionManager verwenden und die LastResourceCommitOptimisation . Es gibt quelloffene JTATransactionManager, die Sie verwenden können, wie JOTM

Dieser JavaWorld-Artikel geht näher auf Ihren Problembereich ein.

1voto

Varun Punkte 89

Obwohl diese Frage bereits ausführlich von Brad beantwortet wurde, möchte ich auf einen ganz bestimmten Teil Ihrer Frage eingehen:-

Ich wusste nicht, wie dies ohne den JtaTransactionManager möglich ist

Aus der Frühjahrsdokumentation:- Wenn eine JTA-Umgebung erkannt wird, wird der JtaTransactionManager von Spring zur Verwaltung von Transaktionen verwendet

https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-jta.html

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X