@Transactional-Methode, die eine andere Methode ohne @Transactional-Anotation aufruft?

83

Ich habe eine Methode in einer Service-Klasse gesehen, die als markiert war @Transactional, aber es wurden auch einige andere Methoden in derselben Klasse aufgerufen, die nicht als markiert waren @Transactional.

Bedeutet dies, dass der Aufruf separater Methoden dazu führt, dass die Anwendung separate Verbindungen zur Datenbank öffnet oder die übergeordnete Transaktion usw. anhält?

Was ist das Standardverhalten für eine Methode ohne Anmerkungen, die von einer anderen Methode mit @TransactionalAnmerkungen aufgerufen wird ?

goe
quelle

Antworten:

110

Wenn Sie eine Methode ohne @Transactionalinnerhalb eines Transaktionsblocks aufrufen , wird die übergeordnete Transaktion mit der neuen Methode fortgesetzt. Es wird dieselbe Verbindung von der übergeordneten Methode (mit @Transactional) und alle in der aufgerufenen Methode verursachten Ausnahmen verwendet (ohne @Transactionalwird die Transaktion wie in der Transaktionsdefinition konfiguriert zurückgesetzt.

Wenn Sie eine Methode mit einer @TransactionalAnnotation von einer Methode @Transactionalinnerhalb derselben Instanz aufrufen , hat das Transaktionsverhalten der aufgerufenen Methoden keine Auswirkungen auf die Transaktion. Wenn Sie jedoch eine Methode mit einer Transaktionsdefinition von einer anderen Methode mit einer Transaktionsdefinition aufrufen und diese sich in verschiedenen Instanzen befindet, folgt der Code in der aufgerufenen Methode den in der aufgerufenen Methode angegebenen Transaktionsdefinitionen.

Weitere Informationen finden Sie im Abschnitt Deklarative Transaktionsverwaltung der Dokumentation von Frühjahrstransaktionen .

Das deklarative Spring-Transaktionsmodell verwendet den AOP-Proxy. Daher ist der AOP-Proxy für die Erstellung der Transaktionen verantwortlich. Der AOP-Proxy ist nur aktiv, wenn die Methoden mit in der Instanz von außerhalb der Instanz aufgerufen werden.

Arun P Johny
quelle
Ist das das Standardverhalten der Feder?
Goe
Ja. Dies ist das Standardverhalten.
Arun P Johny
2
@Tomasz Ja. Es sollte jedoch auch erwähnt werden, dass das Ändern der Transaktionsausbreitung für eine Methode, die von einer anderen @ Transactional-Methode aufgerufen wird, keine Auswirkungen hat.
Fil
1
@Tomasz, das habe ich damit gemeint will follow the transaction definitions given in the called method. Wenn der Aufruf jedoch von derselben Objektinstanz stammt, hat dies keine Auswirkungen, da der Aufruf nicht über die aop-Proxys weitergegeben wird, die für die Transaktionswartung verantwortlich sind.
Arun P Johny
5
@Filip, Das ist nicht ganz richtig. Wenn Sie eine Methode mit einer @TransactionalDefinition von einem anderen Objekt / einer anderen Instanz aufrufen @Transactional, folgt die aufgerufene Methode der eigenen Transaktionsdefinition, obwohl die aufrufende Methode andere Attribute hat.
Arun P Johny
23
  • Bedeutet dies, dass der Aufruf separater Methoden dazu führt, dass die Anwendung separate Verbindungen zur Datenbank öffnet oder die übergeordnete Transaktion usw. anhält?

Das hängt von einem Ausbreitungsgrad ab . Hier sind alle möglichen Pegelwerte .

Wenn beispielsweise eine Weitergabeebene verschachtelt ist, wird eine aktuelle Transaktion " angehalten " und eine neue Transaktion erstellt ( Hinweis: Die tatsächliche Erstellung einer verschachtelten Transaktion funktioniert nur bei bestimmten Transaktionsmanagern ).

  • Was ist das Standardverhalten für eine Methode ohne Annotationen, die von einer anderen Methode mit @ Transactional-Annotation aufgerufen wird?

Die Standardausbreitungsstufe (was Sie "Verhalten" nennen) ist ERFORDERLICH . Wenn eine "innere" Methode aufgerufen wird, die eine @TransactionalAnmerkung enthält (oder deklarativ über XML abgewickelt wird), wird sie innerhalb derselben Transaktion ausgeführt , z. B. wird "nichts Neues" erstellt.

Tolitius
quelle
Was ist mit Unteraufrufen von NOT_SUPPORTED, die keine Anmerkungen enthalten? Erbt es NOT_Supported oder haben sie eine neue Transaktion geöffnet, da REQURED die Standardeinstellung ist? Zum Beispiel: f1.call () {f2 ()} mit der Annotation NOT_SUPPORTED für f1 und non für f2.
Dave
8

@Transactional markiert die Transaktionsgrenze (Anfang / Ende), aber die Transaktion selbst ist an den Thread gebunden. Sobald eine Transaktion gestartet wird, wird sie über Methodenaufrufe verteilt, bis die ursprüngliche Methode zurückgegeben wird und die Transaktion festgeschrieben / zurückgesetzt wird.

Wenn eine andere Methode mit einer @ Transactional-Annotation aufgerufen wird, hängt die Propagation vom Propagation-Attribut dieser Annotation ab.

Sourcedelica
quelle
Die 3 Antworten stehen in gewissem Maße in Konflikt miteinander, nicht sicher, welche genauer ist.
Eric Wang
1
@EricWang Ich wollte nur mitteilen, dass ich dieses Szenario heute getestet habe und die Antwort von Arun P Johny (mit Kommentaren) die genaueste für dieses Szenario interner Aufrufe ist.
Vinay Vissh
3

Die innere Methode wirkt sich auf die äußere Methode aus, wenn die innere Methode nicht mit @Transactional versehen ist.

Falls die innere Methode auch mit @Transactional with kommentiert ist, geschieht REQUIRES_NEWFolgendes.

...
@Autowired
private TestDAO testDAO;

@Autowired
private SomeBean someBean;

@Override
@Transactional(propagation=Propagation.REQUIRED)
public void outerMethod(User user) {
  testDAO.insertUser(user);
  try{
    someBean.innerMethod();
  } catch(RuntimeException e){
    // handle exception
  }
}


@Override
@Transactional(propagation=Propagation.REQUIRES_NEW)
public void innerMethod() {
  throw new RuntimeException("Rollback this transaction!");
}

Die innere Methode ist mit REQUIRES_NEWeiner RuntimeException versehen und löst eine RuntimeException aus, sodass die Transaktion auf Rollback gesetzt wird, die äußere Transaktion jedoch nicht beeinflusst wird. Die äußere Transaktion wird beim Start der inneren Transaktion PAUSED und nach Abschluss der inneren Transaktion fortgesetzt. Sie werden unabhängig voneinander ausgeführt, sodass die äußere Transaktion möglicherweise erfolgreich festgeschrieben wird.

saran3h
quelle
1
Ich bin mir ziemlich sicher, dass sich innerMethod () auf einer anderen Bean (auch bekannt als Spring-Managed Java Object) als OuterMethod () befinden muss. Wenn sich beide auf derselben Bean befinden, verwendet die innerMethod meines Erachtens nicht das in ihrer Annotation deklarierte Transaktionsverhalten. Vielmehr wird verwendet, was in der OuterMethod () - Deklaration deklariert ist. Dies liegt daran, wie Spring mit AOP umgeht, das für seine @ Transactional-Annotationen verwendet wird ( docs.spring.io/spring/docs/3.0.x/spring-framework-reference/… )
johnsimer