it-swarm.com.de

Wohin gehört die Annotation @Transactional?

Sollten Sie den @Transactional in den DAO-Klassen und/oder ihren Methoden platzieren, oder ist es besser, die Service-Klassen zu kommentieren, die mit den DAO-Objekten aufgerufen werden? Oder macht es Sinn, beide "Layer" zu kommentieren?

462

Ich denke, Transaktionen gehören auf die Service-Schicht. Es ist derjenige, der über Arbeitseinheiten und Anwendungsfälle Bescheid weiß. Dies ist die richtige Antwort, wenn mehrere DAOs in einen Service eingefügt werden, die in einer einzigen Transaktion zusammenarbeiten müssen.

480
duffymo

Im Allgemeinen stimme ich mit den anderen überein, dass Transaktionen normalerweise auf der Serviceebene gestartet werden (abhängig von der Granularität, die Sie natürlich benötigen).

In der Zwischenzeit habe ich jedoch auch begonnen, @Transactional(propagation = Propagation.MANDATORY) zu meiner DAO-Schicht hinzuzufügen (und zu anderen Schichten, die keine Transaktionen starten dürfen, aber vorhandene erfordern), da es viel einfacher ist, Fehler zu erkennen, wenn Sie vergessen haben, eine Transaktion im Aufrufer zu starten (zB der Dienst). Wenn Ihr DAO mit einer obligatorischen Weitergabe versehen ist, wird eine Ausnahme angezeigt, die besagt, dass beim Aufruf der Methode keine aktive Transaktion vorhanden ist.

Ich habe auch einen Integrationstest, bei dem ich alle Beans (Bean-Post-Prozessor) auf diese Annotation prüfe und fehlschlage, wenn eine @Transactional-Annotation mit einer anderen Propagation als Mandatory in einer Bean vorhanden ist, die nicht zur Services-Schicht gehört. Auf diese Weise stelle ich sicher, dass wir keine Transaktionen auf der falschen Ebene starten.

282
mnp

Transaktionshinweise sollten um alle untrennbaren Vorgänge herum platziert werden. 

Beispielsweise lautet Ihr Anruf "Kennwort ändern". Das besteht aus zwei Operationen

  1. Änder das Passwort.
  2. Prüfen Sie die Änderung.
  3. E-Mail an den Client, dass das Kennwort geändert wurde.

Sollte also bei der Überprüfung die Überprüfung fehlschlagen, sollte auch die Kennwortänderung fehlschlagen? Wenn ja, dann sollte die Transaktion um 1 und 2 liegen (also auf der Serviceebene). Wenn die E-Mail fehlschlägt (wahrscheinlich sollte dies eine Art Fehler sein, damit sie nicht fehlschlägt), sollte das Änderungskennwort und die Überprüfung zurückgesetzt werden?

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

80
Michael Wiles

Der Normalfall wäre das Annotieren auf Serviceebene, dies hängt jedoch wirklich von Ihren Anforderungen ab.

Das Annotieren auf einer Service-Schicht führt zu längeren Transaktionen als das Annotieren auf DAO-Ebene. Abhängig von der Transaktionsisolationsstufe kann dies zu Problemen führen, da gleichzeitige Transaktionen die Änderungen des anderen nicht in sehen, z. Wiederholbares Lesen.

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

Es ist nicht sinnvoll, beide Ebenen mit Anmerkungen zu versehen, wenn der Ausbreitungsmodus auf "Standard" gesetzt ist.

38
hammarback

Für traditionelle Spring-Architekturen ist es die richtige Antwort, die Transaktionssemantik aus den bereits beschriebenen Gründen in die Serviceklassen einzufügen.

Ein aufkommender Trend im Frühjahr geht in Richtung domänengetriebenes Design (DDD). Spring Roo veranschaulicht den Trend gut. Die Idee ist, die Domänenobjekt-POJOs viel mehr reicher als in typischen Spring-Architekturen (in der Regel anämisch ) zu erstellen, und insbesondere Transaktions- und Persistenzsemantiken für die Domänenobjekte selbst festzulegen. In den Fällen, in denen nur einfache CRUD-Vorgänge erforderlich sind, arbeiten die Web-Controller direkt mit den Domänenobjekt-POJOs (sie fungieren in diesem Zusammenhang als Entitäten), und es gibt keine Service-Schicht. In Fällen, in denen eine Art Koordination zwischen Domänenobjekten erforderlich ist, können Sie eine Service-Bean verwenden, die @Transaction wie üblich verwendet. Sie können die Transaktionsweitergabe für die Domänenobjekte auf etwas wie REQUIRED setzen, sodass die Domänenobjekte alle vorhandenen Transaktionen verwenden, z. B. Transaktionen, die in der Service-Bean gestartet wurden.

Technisch verwendet diese Technik AspectJ und <context:spring-configured />. Roo verwendet AspectJ-Typdefinitionen, um die Entitätssemantik (Transaktionen und Persistenz) von den Domänenobjekten (im Wesentlichen Felder und Geschäftsmethoden) zu trennen.

38
Willie Wheeler

Ich platziere den @Transactional auf der @Service-Ebene und setze rollbackFor eine beliebige Ausnahme und readOnly, um die Transaktion weiter zu optimieren.

Standardmäßig sucht @Transactional nur nach RuntimeException (Unchecked Exceptions). Durch das Zurücksetzen auf Exception.class (Checked Exceptions) wird für alle Ausnahmen ein Rollback ausgeführt.

@Transactional(readOnly = false, rollbackFor = Exception.class)

Siehe Geprüfte vs. ungeprüfte Ausnahmen .

29
user2601995

Oder macht es Sinn, beide "Layer" zu kommentieren? - ist es nicht sinnvoll, sowohl die Service-Schicht als auch die Dao-Schicht zu kommentieren - wenn Sie sicherstellen möchten, dass die DAO-Methode immer von einer Service-Schicht aufgerufen (propagiert) wird, deren Weitergabe in DAO "verbindlich" ist. Dies würde eine Einschränkung für DAO-Methoden bereitstellen, die von der Benutzeroberflächenschicht (oder Controller) aufgerufen werden. Wenn Sie DAO-Layer insbesondere für Unit-Tests verwenden, wird durch das Annotieren von DAO auch sichergestellt, dass die Transaktionsfunktionalität getestet wird.

17
tweekran

Spring empfiehlt außerdem, die Anmerkung nur für konkrete Klassen und nicht für Schnittstellen zu verwenden.

http://static.springsource.org/spring/docs/2.0.x/reference/transaction.html

16
davidemm

Für Transaktion auf Datenbankebene

meistens habe ich @Transactional in DAOs nur auf Methodenebene verwendet, so dass die Konfiguration speziell für eine Methode/Standardeinstellung (erforderlich) erfolgen kann.

  1. DAOs Methode, die Daten abruft (select ..) - braucht nicht @Transactional Dies kann aufgrund von Transaction Interceptor/und AOP-Proxy zu einem gewissen Aufwand führen, der als Well ausgeführt werden muss.

  2. DAOs Methoden, die eingefügt/aktualisiert werden, erhalten @Transactional

sehr guter blog auf transctional

Für Anwendungsebene -
Ich verwende Transactional für die Geschäftslogik. Ich möchte im Falle eines unerwarteten Fehlers zurückholen können

@Transactional(rollbackFor={MyApplicationException.class})
public void myMethod(){

    try {    
        //service logic here     
    } catch(Throwable e) {

        log.error(e)
        throw new MyApplicationException(..);
    }
}
13
lukass77

Normalerweise sollte man eine Transaktion auf die Service-Ebene legen.

Wie bereits gesagt, sagt uns die Atomizität einer Operation, wo eine Anmerkung notwendig ist. Wenn Sie also Frameworks wie Hibernate verwenden, bei denen eine einzelne "Speichern/Aktualisieren/Löschen/...-Änderung" für ein Objekt die Möglichkeit hat, mehrere Zeilen in mehreren Tabellen (aufgrund der Kaskade durch den Objektgraphen) zu ändern, können Sie Folgendes beachten Natürlich sollte es auch ein Transaktionsmanagement für diese spezielle DAO-Methode geben.

12
yannick555

@Transactional Anmerkungen sollten um alle untrennbaren Operationen platziert werden. __ Mit @Transactional wird die Transaktionsweitergabe automatisch behandelt. Wenn in diesem Fall eine andere Methode mit der aktuellen Methode aufgerufen wird, hat diese Methode die Möglichkeit, an der laufenden Transaktion teilzunehmen.

Nehmen wir ein Beispiel:

Wir haben 2 Modelle, d. H. Country und City. Relational Mapping von Country und City Modell ist wie eine Country kann mehrere Städte haben, so dass Mapping wie folgt ist:

@OneToMany(fetch = FetchType.LAZY, mappedBy="country")
private Set<City> cities;

Hier wurde das Land mehreren Städten zugeordnet, wobei diese Lazily abgerufen wurden. Hier kommt also die Rolle von @Transactinal, wenn wir das Country-Objekt aus der Datenbank abrufen. Dann erhalten wir alle Daten des Country-Objekts, aber keine Set-Städte, da die Städte LAZILY abgerufen werden.

//Without @Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //After getting Country Object connection between countryRepository and database is Closed 
}

Wenn wir auf das Set of Cities vom Länderobjekt aus zugreifen möchten, erhalten wir Nullwerte in diesem Set, da das Objekt von Set, das nur dieses Set erstellt wurde, nicht mit seinen Daten initialisiert wird, um Werte von Set abzurufen, die wir verwenden @Transactional, d.

//with @Transactional
@Transactional
public Country getCountry(){
   Country country = countryRepository.getCountry();
   //below when we initialize cities using object country so that directly communicate with database and retrieve all cities from database this happens just because of @Transactinal
   Object object = country.getCities().size();   
}

Grundsätzlich kann @Transactional is Service in einer Transaktion mehrere Anrufe tätigen, ohne die Verbindung mit dem Endpunkt zu schließen.

8
Harshal Patil

Es ist besser, es in der Service-Schicht zu haben! Dies ist in einem der Artikel, die ich gestern gefunden habe, eindeutig erklärt! Hier ist der Link den Sie auschecken können!

7
sundary

Zuerst definieren wir, wo wir transaction verwenden müssen. 

Ich denke, die richtige Antwort lautet: Wenn wir sicherstellen müssen, dass die Reihenfolge der Aktionen zusammen als eine atomare Operation abgeschlossen wird oder keine Änderungen vorgenommen werden, selbst wenn eine der Aktionen fehlschlägt.

Es ist allgemein bekannt, Geschäftslogik in Dienste zu integrieren. Daher können Servicemethoden verschiedene Aktionen enthalten, die als eine einzige logische Arbeitseinheit ausgeführt werden müssen. Wenn ja, dann muss diese Methode als Transactional gekennzeichnet sein. Natürlich ist nicht für jede Methode eine solche Einschränkung erforderlich, sodass Sie nicht den gesamten Service als transactional kennzeichnen müssen. 

Und noch mehr - vergessen Sie nicht zu berücksichtigen, dass @Transactional die Methodenleistung beeinträchtigen kann. Um das Gesamtbild zu sehen, müssen Sie die Isolationsstufen der Transaktion kennen. Wenn Sie wissen, dass dies helfen kann, sollten Sie @Transactional vermeiden, wenn dies nicht unbedingt erforderlich ist.

4
smaiakov

Die Service-Schicht ist der beste Ort, um @Transactional-Anmerkungen hinzuzufügen, da die meisten hier vorgestellten Geschäftslogiken das Verhalten auf Detailebene enthalten.

Nehmen wir an, wir fügen es DAO hinzu, und vom Dienst rufen wir zwei DAO-Klassen auf: eine fehlgeschlagene und andere Erfolge. In diesem Fall würde @Transactional nicht im Dienst eine DB festschreiben und die andere zurücksetzen.

Daher empfiehlt es sich, diese Anmerkung weise zu verwenden und nur auf der Service-Ebene zu verwenden.

Github-Projekt- Java-Algos

4
VishalTambe

Im Idealfall stellt die Service-Schicht (Manager) Ihre Geschäftslogik dar und sollte daher mit @Transactional versehen werden. Die Service-Schicht ruft möglicherweise unterschiedliche DAOs zur Ausführung von DB-Operationen auf. Nehmen wir an, es gibt Situationen, in denen Sie N Anzahl von DAO-Operationen in einer Servicemethode haben. Wenn Ihre erste DAO-Operation fehlgeschlagen ist, werden möglicherweise noch andere übergeben und Sie erhalten den inkonsistenten DB-Status. Durch das Kommentieren der Service-Schicht können Sie sich vor solchen Situationen schützen.

2
salsinga

 enter image description here

Der @Transactional sollte auf Serviceebene verwendet werden, da er die Geschäftslogik enthält. Die DAO-Schicht hat normalerweise nur Datenbank-CRUD-Operationen. 

// the service class that we want to make transactional
@Transactional
public class DefaultFooService implements FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);
}

Spring doc: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/transaction.html

1
Alin

Ich ziehe es vor, @Transactional auf Servicesebene auf Methodenebene zu verwenden.

1
Spark-Beginner

@Transactional verwendet in der Service-Schicht, die unter Verwendung der Controller-Schicht (@Controller) und des Aufrufs der Service-Schicht an die DAO-Schicht (@Repository) aufgerufen wird, d. h. datenbankbezogene Operationen.

1
Satish Suradkar

Es ist besser, @Transactional in einer separaten mittleren Schicht zwischen DAO und Service Layer zu behalten .. Da Rollback sehr wichtig ist, können Sie alle Ihre DB-Manipulationen in der mittleren Schicht platzieren und Geschäftslogik in Service Layer schreiben. Die mittlere Ebene interagiert mit Ihren DAO-Ebenen. 

Dies hilft Ihnen in vielen Situationen, z. B. ObjectOptimisticLockingFailureException - Diese Ausnahmebedingung tritt nur auf, wenn Ihre Transaktion abgeschlossen ist. Sie können es also nicht in der mittleren Ebene fangen, aber Sie können jetzt in Ihrer Service-Ebene fangen. Dies ist nicht möglich, wenn Sie @Transactional in der Service-Schicht haben. Sie können zwar im Controller fangen, der Controller sollte jedoch so sauber wie möglich sein.

Wenn Sie nach Abschluss aller Optionen zum Speichern, Löschen und Aktualisieren von E-Mails oder SMS in einem separaten Thread senden, können Sie dies im Dienst tun, nachdem die Transaktion in Ihrer mittleren Schicht abgeschlossen ist. Wenn Sie @Transactional in der Service-Schicht angeben, werden Ihre E-Mails auch dann gesendet, wenn Ihre Transaktion fehlschlägt. 

Wenn Sie also eine mittlere @Transaction-Ebene haben, wird Ihr Code besser und einfacher zu handhaben sein. Andernfalls, Wenn Sie in der DAO-Schicht verwenden, können Sie möglicherweise nicht alle Vorgänge rückgängig machen . Wenn Sie in der Service-Schicht verwenden, müssen Sie möglicherweise in bestimmten FällenAOP(Aspektorientierte Programmierung) verwenden.