Ich habe Probleme beim Festschreiben einer Transaktion innerhalb meiner @ Transactional-Methode:
methodA() {
methodB()
}
@Transactional
methodB() {
...
em.persist();
...
em.flush();
log("OK");
}
Wenn ich methodB () von methodA () aus aufrufe, ist die Methode erfolgreich und ich kann "OK" in meinen Protokollen sehen. Aber dann verstehe ich
Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Transaction marked as rollbackOnly
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:521)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:754)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:723)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:393)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:120)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:622)
at methodA()...
- Der Kontext von Methode B fehlt in der Ausnahme vollständig - was ist in Ordnung, nehme ich an?
- Etwas in der Methode B () hat die Transaktion nur als Rollback markiert? Wie kann ich das herausfinden? Gibt es zum Beispiel eine Möglichkeit, so etwas zu überprüfen
getCurrentTransaction().isRollbackOnly()?
- so könnte ich die Methode durchgehen und die Ursache finden.
Antworten:
Wenn Sie Ihre Methode als markieren, markiert das
@Transactional
Auftreten einer Ausnahme innerhalb Ihrer Methode den umgebenden TX nur als Rollback (selbst wenn Sie sie abfangen). Sie können andere@Transactional
Annotationsattribute verwenden, um ein Zurücksetzen zu verhindern, wie z.quelle
noRollbackFor=Exception.class
, aber es scheint keine Wirkung zu haben - funktioniert es für geerbte Ausnahmen?methodC
in Ihrem ersten Beitrag nicht angegeben). BeidemethodB
undmethodC
verwenden denselben TX, und es wird immer die spezifischste@Transactional
Anmerkung verwendet. Wenn alsomethodC
die Ausnahme ausgelöst wird, wird der umgebende TX als nur Rollback markiert. Sie können auch verschiedene Ausbreitungsmarker verwenden, um dies zu verhindern.EmptyResultDataAccessException
Ausnahme für eine schreibgeschützte Transaktion ausgelöst, und ich habe den gleichen Fehler erhalten. Ändern meiner Anmerkung, um@Transactional(readOnly = true, noRollbackFor = EmptyResultDataAccessException.class)
das Problem zu beheben.@Transactional
Proxy-Wrapper durchlaufen , dh nicht erfasst werden . Siehe die andere Antwort von Vojtěch für die ganze Geschichte. Es kann verschachtelte@Transactional
Methoden geben, die nur das Transaktions-Rollback markieren können.Ich habe das Problem endlich verstanden:
Was passiert ist, dass, obwohl das
methodB
die richtige Anmerkung hat, dasmethodC
nicht. Wenn die Ausnahme ausgelöst wird,@Transactional
markiert die zweite die erste Transaktion ohnehin nur als Rollback.quelle
propagation=requires_new
dann methodeB wird nicht Rollback?methodC
muss sich in einem anderen Spring Bean / Service befinden oder irgendwie über den Spring Proxy aufgerufen werden. Andernfalls hat Spring keine Möglichkeit, von Ihrer Ausnahme zu erfahren. Nur eine Ausnahme, die eine@Transactional
Anmerkung durchläuft, kann die Transaktion als nur Rollback kennzeichnen.Setzen Sie einen Haltepunkt auf, um die verursachende Ausnahme schnell abzurufen, ohne sie neu codieren oder neu erstellen zu müssen
und gehe in den Stapel, normalerweise zu einem Interceptor. Dort können Sie die verursachende Ausnahme aus einem catch-Block lesen.
quelle
org.hibernate.jpa.internal.TransactionImpl
org.hibernate.engine.transaction.internal.TransactionImpl
und die Methode istsetRollbackOnly
.Ich hatte Probleme mit dieser Ausnahme, während ich meine Anwendung ausführte.
Schließlich lag das Problem bei der SQL-Abfrage . Ich meine, dass die Abfrage falsch ist.
Bitte überprüfen Sie Ihre Anfrage. Das ist mein Vorschlag
quelle
Suchen Sie nach Ausnahmen, die in den
...
Abschnitten Ihres Codes ausgelöst und abgefangen werden. Ausnahmen für Laufzeit- und Rollbacking-Anwendungen verursachen ein Rollback, wenn sie aus einer Geschäftsmethode entfernt werden, selbst wenn sie an einem anderen Ort abgefangen werden.Mithilfe des Kontexts können Sie herausfinden, ob die Transaktion für das Rollback markiert ist.
quelle
SessionContext
eine Standardklasse im Frühling? Mir scheint, es ist eher EJB3 und es ist nicht in meiner Frühlingsanwendung enthalten.TransactionAspectSupport.currentTransactionStatus().isRollbackOnly()
verfügbar sein.Eine gute Erklärung mit Lösungen gefunden: https://vcfvct.wordpress.com/2016/12/15/spring-nested-transactional-rollback-only/
1) Entfernen Sie @Transacional aus der verschachtelten Methode, wenn keine Transaktionssteuerung erforderlich ist. Selbst wenn es eine Ausnahme gibt, sprudelt es nur und hat keinen Einfluss auf das Transaktionsmaterial.
ODER:
2) Wenn eine verschachtelte Methode eine Transaktionssteuerung benötigt, machen Sie sie auf diese Weise zu REQUIRE_NEW für die Weitergaberichtlinie. Selbst wenn eine Ausnahme ausgelöst und nur als Rollback markiert wird, ist der Aufrufer nicht betroffen.
quelle
Deaktivieren Sie den Transaktionsmanager in Ihrer Bean.xml
Wenn Sie diese Zeilen auskommentieren, wird die Ausnahme angezeigt, die den Rollback verursacht.
quelle
Wenden Sie den folgenden Code in productRepository an
@Query("update Product set prodName=:name where prodId=:id ") @Transactional @Modifying int updateMyData(@Param("name")String name, @Param("id") Integer id);
Während des Junit-Tests den folgenden Code anwenden
Es funktioniert gut für meinen Code
quelle