Frage, ich habe dem Dienst wie üblich Anmerkungen hinzugefügt
@Transactional
, warum finde ich beim Abfragen der Datenbank immer noch Dateninkonsistenzen? Es muss sein, dass die Transaktion und die Daten nicht funktioniert haben wurde nicht zurückgegeben, als eine Ausnahmerolle auftrat. Also habe ich den relevanten Code getestet und festgestellt, dass ich in zwei Löcher geraten war. Es lag tatsächlich an der Dateninkonsistenz, die dadurch verursacht wurde, dass die Transaktion nicht zurückgesetzt wurde. Fassen wir die gewonnenen Erkenntnisse im Folgenden zusammen:
Programmatische Transaktionsverwaltung
Wird in tatsächlichen Anwendungen selten verwendet
Transaktionen manuell verwalten, indem Sie TransactionTemplate
Deklarative Transaktionsverwaltung
Empfohlen für die Entwicklung (minimaler Codeeingriff)
Die deklarativen Transaktionen von Spring werden über AOP implementiert
Beherrsche hauptsächlich das deklarative Transaktionsmanagement.
Um die beiden Gründe, warum Transaktionen nicht zurückgesetzt werden, zusammenzufassen: Einer ist der interne Methodenaufruf der Service-Klasse und der andere ist der Versuch ...Ausnahme abfangen.
Wahrscheinlich gibt es eine Methode A in Service, die Methode B intern aufruft, und Methode B verwendet deklarative Transaktionen. Deklarieren Sie eine Transaktionsanmerkung für die Methode zur Transaktionsverwaltung. Der Beispielcode lautet wie folgt:
@Servicepublic class RabbitServiceImpl implements RabbitService { @Autowiredprivate RabbitDao rabbitDao; @Autowiredprivate TortoiseDao tortoiseDao; @Overridepublic Rabbit methodA(String name){return methodB(name); } @Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name){ rabbitDao.insertRabbit(name); tortoiseDao.insertTortoise(name);return true; } }
Der Unit-Testcode lautet wie folgt:
public class RabbitServiceImplTest { @Autowiredprivate RabbitService rabbitService;// 事务未开启 @Testpublic void testA(){ rabbitService.methodA("rabbit"); }// 事务开启 @Testpublic void testB(){ rabbitService.methodB("rabbit"); } }
Wie Sie sehen können Im vorherigen Abschnitt werden deklarative Transaktionen über den dynamischen AOP-Proxy implementiert, der eine Proxy-Klasse für die Transaktionsverwaltung generiert, aber die Zielklasse (der Zieldienst) selbst kann die Existenz der Proxy-Klasse nicht erkennen.
Bei mit @Transactional annotierten Methoden wird beim Aufrufen der Methode der Proxy-Klasse die Transaktion über den Interceptor TransactionInterceptor gestartet und anschließend die Methode der Zielklasse aufgerufen Nach Abschluss wird der TransactionInterceptor eine Transaktion senden oder zurücksetzen. Der allgemeine Prozess ist wie folgt:
Zusammenfassend lässt sich sagen, dass beim Aufrufen von Methode B in Methode A tatsächlich eine Referenz erfolgt Dies bedeutet, dass die Methode der Zielklasse direkt anstelle der über den Spring-Kontext erhaltenen Proxy-Klasse aufgerufen wird, sodass die Transaktion nicht gestartet wird.
behandelt die Datenbankausnahme in einer Geschäftslogik, verwendet die try...catch-Klausel, um die Ausnahme zu erfassen und löst eine benutzerdefinierte Ausnahme aus Die Situation führte dazu, dass die Transaktion nicht zurückgesetzt wurde. Der Beispielcode lautet wie folgt:
@Transactional(propagation = Propagation.REQUIRED)public boolean methodB(String name) throws BizException {try { rabbitDao.insertRabbit(name); tortoiseDao.insertTortoise(name); } catch (Exception e) {throw new BizException(ReturnCode.EXCEPTION.code, ReturnCode.EXCEPTION.msg); }return true; }
Die Definition von BizException lautet wie folgt:
public class BizException extends Exception {// 自定义异常}
Die deklarative Transaktion im obigen Code wird nicht zurückgesetzt, wenn eine Ausnahme auftritt. Obwohl ich die Ausnahme im Code abgefangen habe, habe ich gleichzeitig auch eine Ausnahme ausgelöst. Warum wurde die Transaktion nicht zurückgesetzt? Ich vermutete, dass der Ausnahmetyp falsch war, also begann ich nach dem Grund zu suchen, schaute mir die offizielle Dokumentation von Spring an und fand die Antwort. Das Folgende wurde von der offiziellen Spring-Website übersetzt.
Im vorherigen Abschnitt wurde erläutert, wie Sie Spring-Transaktionen einrichten, die im Allgemeinen im Service-Layer-Code Ihrer Anwendung festgelegt werden. In diesem Abschnitt wird die Steuerung erläutert Transaktions-Rollback in einfachen und beliebten deklarativen Transaktionen.
Die empfohlene Transaktions-Rollback-Methode im Transaktions-Framework von Spring FrameWork besteht darin, eine Ausnahme im Kontext der aktuell ausgeführten Transaktion auszulösen. Wenn die Ausnahme nicht behandelt wird, fängt der Transaktions-Framework-Code von Spring FrameWork jede nicht behandelte Ausnahme ab, wenn die Ausnahme im Aufrufstapel ausgelöst wird, und entscheidet dann, ob die Transaktion für ein Rollback markiert werden soll.
In der Standardkonfiguration markiert der Transaktions-Framework-Code von Spring FrameWork nur Transaktionen mit runtime, unchecked
Ausnahmen als zurückgesetzt; das heißt, die in der Transaktion ausgelösten Ausnahmen sind RuntimeException oder Ist seine Unterklasse, sodass die Transaktion zurückgesetzt wird (Fehler führt auch dazu, dass die Transaktion standardmäßig zurückgesetzt wird). Mit der Standardkonfiguration führen alle aktivierten Ausnahmen nicht zu einem Transaktions-Rollback.
Hinweis: Unchecked Exception umfasst Error und RuntimeException. Alle Unterklassen von RuntimeException gehören ebenfalls zu dieser Kategorie. Der andere Typ ist eine aktivierte Ausnahme.
Sie können den Ausnahmetyp genau konfigurieren und ein Transaktions-Rollback für diesen Ausnahmetyp festlegen, einschließlich geprüfter Ausnahmen. Der folgende XML-Codeausschnitt zeigt, wie überprüfte Ausnahmen konfiguriert werden, um ein Transaktions-Rollback zu verursachen und benutzerdefinierte Ausnahmetypen anzuwenden:
<advice> <attributes> <method></method> <method></method> </attributes> </advice>
Anmerkungsformular mit demselben Effekt Wie folgt :
@Transactional(rollbackForClassName={"Exception"}) 或者 @Transactional(rollbackFor={Exception.class})
在你遇到异常不想回滚事务的时候,同样的你也可指定不回滚的规则,下面的一个例子告诉你,即使遇到未处理的 InstrumentNotFoundException
异常时,Spring FrameWork 的事务框架同样会提交事务,而不回滚。
<advice> <attributes> <method></method> <method></method> </attributes> </advice>
与其有同样作用的注解形式如下:
@Transactional(noRollbackForClassName={"InstrumentNotFoundException"}) 或者 @Transactional(noRollbackFor={InstrumentNotFoundException.class})
还有更灵活的回滚规则配置方法,同时指定什么异常回滚,什么异常不回滚。当Spring FrameWork 的事务框架捕获到一个异常的时候,会去匹配配置的回滚规则来决定是否标记回滚事务,使用匹配度最强的规则结果。因此,下面的配置例子表达的意思是,除了异常 InstrumentNotFoundException
之外的任何异常都会导致事务回滚。
<advice> <attributes> <method></method> </attributes> </advice>
你也可以通过编程式的方式回滚一个事务,尽管方法非常简单,但是也有非常强的代码侵入性,使你的业务代码和Spring FrameWork 的事务框架代码紧密的绑定在一起,示例代码如下:
public void resolvePosition() { try { // some business logic... } catch (NoProductInStockException ex) { // trigger rollback programmatically TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } }
如果可能的话,强烈推荐您使用声明式事务方式回滚事务,对于编程式事务,如果你强烈需要它,也是可以使用的,but its usage flies in the face of achieving a clean POJO-based architecture.(没懂...)
看完官方文档这节内容找到了问题的答案,原来是因为我们自定义的异常不是 RuntimeException
。我的解决办法是,在注解@Transactional
中添加 rollbackFor={BizException.class}
。可能你会问我为什么不将自定义异常修改为继承RuntimeException,因为我需要BizException是一个checked 异常。
Das obige ist der detaillierte Inhalt vonBetriebsmethode für das Spring-Transaktionsmanagement. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!