Hallöle liebe Leute,
ich hab eine kleine Frage zu Transaktionen in Spring.
Ich schreibe zur Zeit eine Webanwendung, in welcher man Artikel auf Aufträge und auf Rechnungen buchen kann.
Das Buchen eines Artikels soll dabei auch den Bestand des Artikels verändern.
So weit, so gut. Man hätte also drei Methoden die in etwa so aussehen:
Der Quellcode hier ist vollkommen fiktiv aber es geht mir um folgendes:
Es gibt nun zwei Funktionen welche etwas sehr ähnliches tun.
Die erste Methode "erstelleArtikelFuerAuftrag" erstellt einen Auftragsartikel und verändert danach den Bestand und die zweite Methode "erstelleArtikelFuerRechnung" erstellt einen Rechnungsartikel und verändert danach den Bestand.
Beide Methoden verwenden also die Methode "aendereBestand".
Es sollte nun so sein, dass diese Methode nie mehrmals gleichzeitig aufgerufen wird, da es sonst zu Fehlern im Bestand kommen könnte.
Nun zu meiner Frage: "Ist das durch @Transactional bei der Methode aendereBestand gegeben?"
Ich tue mir sehr schwer das zu testen aber vermute, dass das NICHT der Fall ist.
Denn:
Die Transaktionen werden bereits beim Aufruf der Methoden "erstelleArtikelFuerAuftrag" und "erstelleArtikelFuerRechnung" erstellt. Beim Aufruf der Transaktion "aendereBestand" wird KEINE NEUE Transaktion erstellt, sondern die alte weiter verwendet. Ich habe aber leider keine Ahnung ob sich diese beiden Transaktionen beim Aufrufen von "aendereBestand" als Lock erkennen.
Weiß das jemand?
Ich habe etwas im Internet gesucht und dachte zuerst ich könnte propagation.REQUIRES_NEW verwenden jedoch ist die Gesamttransaktion dann nicht mehr atomar. Es wird nämlich dann eine neue Transaktion erstellt und die alte wird suspended. Sollte nun die "innere" Transaktion fehlschlagen wird die darüber liegende keinen Rollback erfahren.
Was meint ihr?
Macht es Sinn in der aendereBestand Methode mit "propagatio.REQUIRES_NEW" zu markieren, einfach eine Exception zu werfen, falls was schief geht, damit einen Rollback zu erzwingen und dann die Exception in der Ober-Methode abzufangen und dort auch einen Rollback zu erzwingen?
Bin mir echt nicht sicher.
Vor allem wegen folgenden Aussagen:
1) Spring Transaktionen Beschreibung (Zitat aus Abschnitt: 10.5.6.1)
Unter 10.5.7 findet man dann auch die Beschreibung der verschiedenen Propagation Werte.
2) IBM Blog zu Spring Transaktionen (Zitat aus Abschnitt: "REQUIRES_NEW transaction attribute pitfalls")
Könnt ihr mir Erleuchtung bringen?
lg
ich hab eine kleine Frage zu Transaktionen in Spring.
Ich schreibe zur Zeit eine Webanwendung, in welcher man Artikel auf Aufträge und auf Rechnungen buchen kann.
Das Buchen eines Artikels soll dabei auch den Bestand des Artikels verändern.
So weit, so gut. Man hätte also drei Methoden die in etwa so aussehen:
Java:
@Transactional(propagation=Propagation.REQUIRED)
public void erstelleArtikelFuerAuftrag( Auftrag auftrag, Artikel artikel ) {
//hier wird ein Artikel für einen Auftrag erstellt
...
//hier wird die Bestandsänderungsmethode aufgerufen
aendereBestand( artikel );
}
@Transactional(propagation=Propagation.REQUIRED)
public void erstelleArtikelFuerRechnung( Rechnung rechnung, Artikel artikel ) {
//hier wird ein Artikel für eine Rechnung erstellt
...
//hier wird die Bestandsänderungsmethode aufgerufen
aendereBestand( artikel );
}
@Transactional(propagation=Propagation.REQUIRED)
public void aendereBestand( Artikel artikel ) {
//hier wird der Bestand dann tatsächlich verändert
...
}
Der Quellcode hier ist vollkommen fiktiv aber es geht mir um folgendes:
Es gibt nun zwei Funktionen welche etwas sehr ähnliches tun.
Die erste Methode "erstelleArtikelFuerAuftrag" erstellt einen Auftragsartikel und verändert danach den Bestand und die zweite Methode "erstelleArtikelFuerRechnung" erstellt einen Rechnungsartikel und verändert danach den Bestand.
Beide Methoden verwenden also die Methode "aendereBestand".
Es sollte nun so sein, dass diese Methode nie mehrmals gleichzeitig aufgerufen wird, da es sonst zu Fehlern im Bestand kommen könnte.
Nun zu meiner Frage: "Ist das durch @Transactional bei der Methode aendereBestand gegeben?"
Ich tue mir sehr schwer das zu testen aber vermute, dass das NICHT der Fall ist.
Denn:
Die Transaktionen werden bereits beim Aufruf der Methoden "erstelleArtikelFuerAuftrag" und "erstelleArtikelFuerRechnung" erstellt. Beim Aufruf der Transaktion "aendereBestand" wird KEINE NEUE Transaktion erstellt, sondern die alte weiter verwendet. Ich habe aber leider keine Ahnung ob sich diese beiden Transaktionen beim Aufrufen von "aendereBestand" als Lock erkennen.
Weiß das jemand?
Ich habe etwas im Internet gesucht und dachte zuerst ich könnte propagation.REQUIRES_NEW verwenden jedoch ist die Gesamttransaktion dann nicht mehr atomar. Es wird nämlich dann eine neue Transaktion erstellt und die alte wird suspended. Sollte nun die "innere" Transaktion fehlschlagen wird die darüber liegende keinen Rollback erfahren.
Was meint ihr?
Macht es Sinn in der aendereBestand Methode mit "propagatio.REQUIRES_NEW" zu markieren, einfach eine Exception zu werfen, falls was schief geht, damit einen Rollback zu erzwingen und dann die Exception in der Ober-Methode abzufangen und dort auch einen Rollback zu erzwingen?
Bin mir echt nicht sicher.
Vor allem wegen folgenden Aussagen:
1) Spring Transaktionen Beschreibung (Zitat aus Abschnitt: 10.5.6.1)
Currently you cannot have explicit control over the name of a transaction, where 'name' means the transaction name that will be shown in a transaction monitor, if applicable (for example, WebLogic's transaction monitor), and in logging output. For declarative transactions, the transaction name is always the fully-qualified class name + "." + method name of the transactionally-advised class. For example, if the handlePayment(..) method of the BusinessService class started a transaction, the name of the transaction would be: com.foo.BusinessService.handlePayment.
Unter 10.5.7 findet man dann auch die Beschreibung der verschiedenen Propagation Werte.
2) IBM Blog zu Spring Transaktionen (Zitat aus Abschnitt: "REQUIRES_NEW transaction attribute pitfalls")
Listing 11. Using the REQUIRES_NEW transaction attribute
Java:@Transactional(propagation=Propagation.REQUIRES_NEW) public long insertTrade(TradeData trade) throws Exception {...} @Transactional(propagation=Propagation.REQUIRES_NEW) public void updateAcct(TradeData trade) throws Exception {...}
Notice in Listing 11 that both of these methods are public, implying that they can be invoked independently from each other. Problems occur with the REQUIRES_NEW attribute when methods using it are invoked within the same logical unit of work via inter-service communication or through orchestration. For example, suppose in Listing 11 that you can invoke the updateAcct() method independently of any other method in some use cases, but there's also the case where the updateAcct() method is also invoked in the insertTrade() method. Now, if an exception occurs after the updateAcct() method call, the trade order would be rolled back, but the account updates would be committed to the database, as shown in Listing 12:
Listing 12. Multiple updates using the REQUIRES_NEW transaction attribute
Java:@Transactional(propagation=Propagation.REQUIRES_NEW) public long insertTrade(TradeData trade) throws Exception { em.persist(trade); updateAcct(trade); //exception occurs here! Trade rolled back but account update is not! ... }
This happens because a new transaction is started in the updateAcct() method, so that transaction commits once the updateAcct() method ends. When you use the REQUIRES_NEW transaction attribute, if an existing transaction context is present, the current transaction is suspended and a new transaction started. Once that method ends, the new transaction commits and the original transaction resumes.
Könnt ihr mir Erleuchtung bringen?
lg