598 Stimmen

Wo gehört die @Transactional-Anmerkung hin?

Sollten Sie die @Transactional im DAO Klassen und/oder deren Methoden oder ist es besser, die Dienstklassen zu annotieren, die die DAO-Objekte verwenden? Oder ist es sinnvoll, beide "Schichten" zu annotieren?

601voto

duffymo Punkte 298898

Meiner Meinung nach gehören Transaktionen in die Diensteschicht. Sie ist diejenige, die sich mit Arbeitseinheiten und Anwendungsfällen auskennt. Es ist die richtige Antwort, wenn Sie mehrere DAOs in einen Dienst injiziert haben, die in einer einzigen Transaktion zusammenarbeiten müssen.

0 Stimmen

Dem stimme ich zu. Manchmal spielt es keine Rolle, aber manchmal kann man davon profitieren, z.B. wenn die Hibernate-Sitzung während der Transaktion überbrückt wird, so dass alle geladenen Objekte im 1st-Level-Cache sind und man die Objekte nicht wieder an die Sitzung anhängen muss, und wenn die faul geladenen Eigenschaften ohne Unschärfe funktionieren.

7 Stimmen

Kann eine globale Transaktion aus mehr als einer dieser @Transactional(propagation = Propagation.REQUIRED) bestehen? Oder ist @Transactional immer eine Begrenzung für eine Transaktion? Ich bin mir nicht sicher, ob ich es aus der Dokumentation verstanden habe, aber es scheint so, dass man sogar Transaktionen erstellen kann, die aus @Transactional-Methoden bestehen und alles, was darin läuft

1 Stimmen

Ja, ich denke, das äußerste @Transactional ist dasjenige, das zur Grenze für die Transaktion wird, wenn Propagation.REQUIRED eingeschaltet ist.

324voto

mnp Punkte 3212

Im Allgemeinen stimme ich den anderen zu, die sagen, dass Transaktionen in der Regel auf der Dienstebene gestartet werden (natürlich abhängig von der von Ihnen benötigten Granularität).

In der Zwischenzeit habe ich jedoch auch damit begonnen, die @Transactional(propagation = Propagation.MANDATORY) zu meiner DAO-Schicht (und anderen Schichten, die keine Transaktionen starten dürfen, aber bestehende benötigen), weil es viel einfacher ist, Fehler zu erkennen, bei denen Sie vergessen haben, eine Transaktion im Aufrufer (z.B. dem Dienst) zu starten. Wenn Ihre DAO mit obligatorischer Propagierung annotiert ist, erhalten Sie eine Ausnahme, die besagt, dass es keine aktive Transaktion gibt, wenn die Methode aufgerufen wird.

Ich habe auch einen Integrationstest, bei dem ich alle Bohnen (Bean Postprozessor) für diese Anmerkung überprüfen und fehlschlagen, wenn es eine @Transactional Annotation mit einer anderen Propagierung als Mandatory in einer Bean, die nicht zur Serviceschicht gehört. Auf diese Weise stelle ich sicher, dass wir keine Transaktionen in der falschen Schicht starten.

3 Stimmen

Sollte dies in der Dao-Schicht (Schnittstellen), in der Dao-Impl.-Schicht oder in beiden erfolgen?

3 Stimmen

Ich weiß nicht, ob es in diese Diskussion passt, aber ein weiterer Tipp könnte sein, @Transactional(readOnly = true) in der Dao-Impl in den nicht-schreibenden Operationen hinzuzufügen.

11 Stimmen

@Johan Spring rät, die Transaktionsannotationen auf die Implementierungsklassen statt auf die Schnittstellen zu legen.

108voto

Michael Wiles Punkte 20303

Transaktionsanmerkungen sollten um alle Operationen herum platziert werden, die untrennbar sind.

Ein Beispiel: Ihr Aufruf lautet "Passwort ändern". Das besteht aus zwei Vorgängen

  1. Ändern Sie das Passwort.
  2. Prüfen Sie die Änderung.
  3. Senden Sie dem Kunden eine E-Mail, dass sich das Passwort geändert hat.

Wenn also in diesem Fall die Prüfung fehlschlägt, sollte dann auch die Passwortänderung fehlschlagen? Wenn ja, dann sollte die Transaktion bei 1 und 2 liegen (also auf der Dienstebene). Wenn die E-Mail fehlschlägt (wahrscheinlich sollte eine Art Failsafe dafür vorhanden sein, damit sie nicht fehlschlägt), sollte sie dann die Kennwortänderung und die Prüfung zurücknehmen?

Dies sind die Fragen, die Sie sich stellen müssen, wenn Sie entscheiden, wo Sie die @Transactional .

41voto

Die richtige Antwort für traditionelle Spring-Architekturen ist, die transaktionale Semantik auf die Service-Klassen zu legen, aus den Gründen, die andere bereits beschrieben haben.

Im Frühjahr zeichnet sich ein neuer Trend ab: die domänenorientiertes Design (DDD). Federvieh ist ein gutes Beispiel für diesen Trend. Die Idee ist, das Domänenobjekt POJOs eine Menge zu machen reicher als bei typischen Spring-Architekturen (normalerweise sind sie anämisch ), und insbesondere die Semantik von Transaktionen und Persistenz auf die Domänenobjekte selbst zu übertragen. In Fällen, in denen nur einfache CRUD-Operationen benötigt werden, arbeiten die Web-Controller direkt auf den Domänenobjekt-POJOs (sie funktionieren in diesem Kontext als Entitäten), und es gibt keine Service-Ebene. In Fällen, in denen eine Art von Koordination zwischen Domänenobjekten erforderlich ist, können Sie eine Service-Bean damit beauftragen, mit @Transaction wie es Tradition ist. Sie können die Transaktionsausbreitung auf den Domänenobjekten auf etwas wie REQUIRED damit die Domänenobjekte alle vorhandenen Transaktionen verwenden, z. B. Transaktionen, die in der Service-Bean gestartet wurden.

Technisch gesehen macht diese Technik Gebrauch von AspectJ und <context:spring-configured /> . Roo verwendet AspectJ-Inter-Type-Definitionen, um die Semantik der Entitäten (Transaktionen und Persistenz) von den Domänenobjekten (im Wesentlichen Felder und Geschäftsmethoden) zu trennen.

41voto

hammarback Punkte 753

Der Normalfall wäre, auf der Ebene der Dienstebene Anmerkungen zu machen, aber das hängt wirklich von Ihren Anforderungen ab.

Das Annotieren auf einer Dienstschicht führt zu längeren Transaktionen als das Annotieren auf DAO-Ebene. Abhängig von der Transaktionsisolationsebene kann dies zu Problemen führen, da konkurrierende Transaktionen die Änderungen der anderen nicht sehen, z.B. bei REPEATABLE READ.

Durch das Annotieren der DAOs werden die Transaktionen so kurz wie möglich gehalten, mit dem Nachteil, dass die Funktionalität, die Ihre Serviceschicht bereitstellt, nicht in einer einzigen (rollbackfähigen) Transaktion ausgeführt wird.

Es ist nicht sinnvoll, beide Ebenen zu beschriften, wenn der Ausbreitungsmodus auf Standard eingestellt ist.

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