簡體   English   中英

Spring 事務和嘗試捕獲塊

[英]Spring transaction and try catch blocks

我對 Kotlin 和 Spring 非常陌生,並且有一個非常基本的疑問。 考慮這樣的 function:

@transaction
fun accept() {
    try {
        write to table A
        throw Exception()
    } catch(){
        write to table B
    }
}

問題:我知道B表寫會成功,但是A表會寫成功嗎? 為什么? 任何指向

Spring 對異常的“含義”有點奇怪。 它的作用如下。 事務方法在退出之前不會提交任何內容。 即:

@transaction
fun accept() {
  write to table A
  while (true) {} // loop forever
}

微不足道地從不實際提交任何東西,這可能很明顯。 否則,該方法退出,它可以通過以下三種方式之一退出:

  • 方法“返回”。 就像在方法中一樣,不會拋出異常 - 可能會拋出異常,但它們會被捕獲。 然后在退出該方法時,事務被提交。 請注意,這描述了您的代碼段——它不會方法中拋出異常 因此,對表 A 和 B 的寫入都將發生並且對外部各方可見!
  • 該方法通過拋出一個 UNCHECKED 異常來結束。 Spring 的觀點是,這是“意外”,並表明執行該方法的結果是失敗 - 整個事務被中止。 對表 A 的寫入永遠不會對其他事務可見,對表 B 的寫入也不可見(假設在 catch 塊之后,您throw new RuntimeException() )。
  • 該方法以拋出一個 CHECKED 異常結束。 Spring 的觀點是,這一定意味着它是“故意的”,並且表明代碼成功; 它只是選擇“返回”異常而不是正常完成。 事務已提交 - 其他人可以看到對表 A 的寫入。 其他人也可以看到對表 B 的寫入(這是假設您將throw new IOException()添加到 accept 方法的末尾,當然您的方法可以這樣做。在 java 中意味着它必須當然,被聲明為void accept() throws IOException {}

kotlin中不存在已檢查和未檢查的概念 - 在 kotlin 中,所有異常都是“未檢查”,有效。 但是,spring 沒有 go:“OOoooohhhh,kotlin 用戶,我將把所有事情都視為未選中的事務,即拋出任何異常,” 不,因此,即使您只編寫 kotlin,您也必須了解檢查異常是什么

Unchecked exceptions are all throwables that have in their type hierarchy either java.lang.Error (such as java.lang.InternalError , which extends jlError ), or java.lang.RuntimeException , such as NullPointerException .

所有其他投擲物都被“檢查”。 比如IOException ,它擴展了 Exception。 它擴展了 Throwable。 檢查Exception本身。

注意:您可以添加攔截器等來改變這種行為; “檢查異常意味着我們需要提交,檢查意味着我們需要中止”只是默認行為。

如果“寫入表 A”成功,那么是的,它將持續存在。

為什么? 因為事務划分是由對異常起作用的攔截器完成的,並且在您的代碼中沒有攔截器會看到該異常,因為它們只能圍繞那些“寫入表 X”調用(如果這些調用是通過可攔截代碼完成的)或accept()執行。

讓我嘗試添加更多細節:

一般來說,您可以在概念上認為攔截器看起來像這樣(它們看起來不同,但示例用於說明這一點 - 我還將使用 Java 代碼,因為我對 Kotlin 不太熟悉):

void runInTransaction(Runnable interceptedCode) {
  Transaction tx = startTransaction();

  try {
    interceptedCode.run();
    tx.commit();
  } catch( Exception e) { //kept simple for illustration purposes, in reality this is way more complex
    tx.rollback();
  }
}

然后你會這樣稱呼它:

runInTransaction(() -> accept());

如您所見,由於異常僅在accept()中被拋出和捕獲 - 因此不會離開方法 - 攔截器甚至不會看到它,因此將提交事務。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM