spring事務管理的一些注意點

2021-09-23 17:56:01 字數 3356 閱讀 9454

總結一些自己最近在使用spring事務管理時碰到的一些注意點

目標類的介面和實現**示例:

public inte***ce aservice 

@service()

public class aserviceimpl implements aservice

@transactional(rollbackfor=)

public void b()

}

只要給目標類aserviceimpl的某個方法加上註解@transactional,spring就會為目標類生成對應的**類,以後呼叫aserviceimpl中的所有方法都會先走**類(即使呼叫未加事務註解的方法a,也會走**類),即在通過getbean("aserviceimpl")獲得的業務類時,實際上得到的是乙個**類,假設這個類叫做aserviceimplproxy ,spring為aserviceimpl生成的**類類似於如下**:

public class aserviceimplproxy implements aservice

public void b()

}

由於目標類中只有b方法加入了事務管理,所以**類中只為b方法加入了橫切事務邏輯,spring事務管理的本質是通過aop為目標類生成動態**類,並在需要進行事務管理的方法中加入事務管理的橫切邏輯**(如aserviceimplproxy中的b方法所示)。

呼叫getbean("aserviceimpl").a()時,實際上執行的是aserviceimplproxy.a(),**類的a方法會通過反射呼叫目標類的a方法, 再在目標類的a方法中呼叫b方法,故最終a中呼叫的b方法是來自於aserviceimpl中的b方法,aserviceimpl的b方法並沒有橫切事務邏輯**(切記:事務邏輯**在**類中,@transactional只是標記此方法在**類中要加入事務邏輯**)。所以呼叫a方法時,b方法的事務會失效。

其實,在proxy物件與目標物件之間還有乙個invocationhandler物件(以jdk動態**為例),真正的橫切邏輯是放到invocationhandler物件中的,呼叫邏輯分離到invocationhandler中主要是為了構造出具有通用性和簡單性的**類,此處為了簡化處理過程,統一放到**物件中來說明,動態**簡化的呼叫關係圖如下:

aop中存在方法巢狀呼叫時,相應的呼叫過程序列圖如下:

對1中的**做修改,為a方法也加上事務註解:

@service()

public class aserviceimpl implements aservice)

public void a()

@transactional(rollbackfor=)

public void b()

}

此時生成的**類類似如下**:

public class aserviceimplproxy implements aservice

public void b()

}

即為a和b都加入了事務橫切邏輯。在這種情況下,呼叫順序還和1中情形類似,區別在於在反射呼叫目標物件的a方法前,會對a方法開啟事務管理,雖然呼叫的b方法還是目標物件中沒有加事務邏輯的**,spring卻會把b合併到a的事務中去,此時相當於只有乙個事務。

如果再將目標類**改為:

@service()

public class aserviceimpl implements aservice)

public void a()

public void b()

}

即只在a上加事務控制,由於b會合併到a的事務中,所以b中的邏輯也可以被事務管理。

由於a和b都合併到了a的事務中,所以這種情形下事務傳遞規則不適用。**類中加了事務邏輯的b方法永遠不會被呼叫。

那麼問題來了,如果我想讓b也執行自己的事務邏輯,即呼叫b時執行**類中b方法的事務邏輯,該怎麼辦?

修改目標類中的a方法:

@transactional(rollbackfor=)

public void a()

這時,就會強制要求呼叫**類中的b方法,從而開啟b上的事務,此時b事務上標註的事務傳遞規則也就可以生效了,詳情參見:

個人覺得這種方法不太好,會汙染業務邏輯**,使**變複雜。

還有一種辦法就是介面下沉,把b方法分離到另乙個介面中,從根源上避免目標物件內部方法自我呼叫。

有時需要在業務邏輯**中顯式try catch包裹事務**,以便在出現異常時進行一些別的處理。

目標類的介面和實現示例**如下:

public inte***ce aservice 

@service()

public class aserviceimpl implements aservice)

public void a() catch(exception e)}}

自己在**中顯式捕獲異常會導致spring事務回滾失效,原因:spring事務是通過aop捕獲到異常後再執行回滾,如果業務**中顯式捕獲了異常,會導致spring捕獲不到,回滾自然失敗。

有如下幾種解決辦法:

(1)業務**catch住異常後重新丟擲,如:

public void a() throws exceptioncatch(exception e)

}

不足是本方法的呼叫端也必須顯式捕獲異常。

(2)使用程式設計式事務顯式回滾:

public void a() catch(exception e)

}

不足是事務控制**會侵入業務**,也正是因為程式設計式事務管理會侵入業務邏輯**,所以才有了申明式事務管理。

(3)介面下沉,將需要事務控制的**分到另乙個介面方法中,如:

public inte***ce bservice 

@service()

public class bserviceimpl implements bservice)

public void b()

}

相應的呼叫端a方法中變為:

public void a() throws exceptioncatch(exception e)

}

Spring宣告式事務管理的一些事

對於read only的真實理解 推薦帖子 靠底層的jdbc驅動和資料庫的支援。在大多數資料庫系統下,唯讀事務裡面是不可以修改資料,並且,在同乙個事務裡面同乙個sql讀出來的同一條記錄是不會變化的,這是我們開啟readonly最重要的原因 我們需要能夠可重複讀。它是效能優化的推薦配置。對於沒有執行資...

spring事務管理(一)

platformtransactionmanager 事務管理器 transactiondefinition 事務定義資訊 隔離 傳播 超時 唯讀 transactionstatus 事務具體執行狀態 spring為不同的持久化框架提供了不同的platformtransactionmanager.內...

Spring事務管理

spring是ssh中的管理員,負責管理其它框架,協調各個部分的工作。今天一起學習一下spring的事務管理。spring的事務管理分為宣告式跟程式設計式。宣告式就是在spring的配置檔案中進行相關配置 程式設計式就是用註解的方式寫到 裡。下面先說宣告式 spring配置檔案中關於事務配置總是由三...