搜尋
首頁Javajava教程Spring事務的深入解析(附範例)

這篇文章帶給大家的內容是關於Spring事務的深入解析(附範例),有一定的參考價值,有需要的朋友可以參考一下,希望對你有幫助。

Spring事務管理我相信大家都用得很多,但可能只限於一個@Transactional註解或是在XML中配置事務相關的東西。不管怎麼說,日常可能足夠我們去用了。但身為程式設計師,無論是為了面試或說更好把控自己寫的程式碼,還是應該得多多了解Spring事務的一些細節。

這裡我拋出幾個問題,看大家能不能瞬間答得上:

  • #如果嵌套呼叫含有交易的方法,在Spring事務管理中,這屬於哪個知識點?

  • 我們使用的框架可能是Hibernate/JPA或是Mybatis,都知道的底層是需要一個session/connection 物件來幫我們執行操作的。要確保事務的完整性,我們需要多組資料庫操作要使用同一個session/connection對象,而我們又知道Spring IOC所管理的對象預設都是單例的,這為啥我們在使用的時候不會引發線程安全問題呢?內部Spring到底做了什麼?

  • 人家所說的BPP又是啥東西?

  • Spring事務管理重要介面有哪幾個?

一、閱讀本文需要的基礎知識

#閱讀這篇文章的同學我預設大家都對Spring事務相關知識有一定的了解了。 (ps:如果不了解點解具體的文章去閱讀再回到這裡來哦)

我們都知道,Spring事務是Spring AOP的最佳實踐之一,所以說AOP入門基礎知識(簡單配置,使用)是需要先知道的。如果想更全面了解AOP可以看這篇文章:AOP重要知識點(術語介紹、全面使用)。說到AOP就不能不說AOP底層原理:動態代理設計模式。到這裡,對AOP已經有一個基礎的認識了。於是我們就可以使用XML/註解方式來設定Spring事務管理。

在IOC學習中,可以知道的是Spring中Bean的生命週期(引出BPP物件)且IOC所管理的物件預設都是單例的:單例設計模式,單例物件如果有" 狀態"(有成員變數),那麼多執行緒存取這個單例對象,可能就造成執行緒不安全。那麼何為線程安全? ,解決線程安全有很多方式,但其中有一個:讓每個線程都擁有自己的一個變數:ThreadLocal

如果對我以上說的知識點不太了解的話,建議點擊藍字進去學習一番。

二、兩個不靠譜直覺的例子

2.1第一個例子

之前朋友問了我一個例子:

在Service層拋出Exception,在Controller層捕獲,那如果在Service中有異常,那會交易回滾嗎?

// Service方法
    
@Transactional
public Employee addEmployee() throws Exception {

    Employee employee = new Employee("3y", 23);
    employeeRepository.save(employee);
    // 假设这里出了Exception
    int i = 1 / 0;

    return employee;
}

// Controller调用
@RequestMapping("/add")
public Employee addEmployee() {
    Employee employee = null;
    try {
        employee = employeeService.addEmployee();
    } catch (Exception e) {
        e.printStackTrace();
    }
    return employee;

}

第一反應:不會回滾吧。

  • 我當時是這樣想的:因為Service層已經拋出了異常,由Controller捕捉。那是否回滾應該由Controller的catch程式碼區塊中邏輯來決定,如果catch程式碼區塊沒有回滾,那應該是不會回滾。

但朋友經過測試說,可以回滾阿。 (pappapa打臉)

Spring事務的深入解析(附範例)

看了一下文檔,原來文檔有說明:

By default checked exceptions do not result in the transactional interceptor marking the transaction for rollback and instances of RuntimeException and its subclasses do

結論:如果是編譯時異常不會自動回滾,如果是執行時間異常,那會自動回滾

2.2第二個例子

第二個例子來自於知乎@柳樹文章,文末會給出對應的URL

我們都知道,帶有@Transactional註解所包圍的方法就能被Spring事務管理起來,那如果我在當前類別下使用一個沒有事務的方法去調用一個有事務的​​方法,那我們這次呼叫會怎麼樣?是否會有事務呢?

用程式碼來描述一下:

// 没有事务的方法去调用有事务的方法
public Employee addEmployee2Controller() throws Exception {

    return this.addEmployee();
}

@Transactional
public Employee addEmployee() throws Exception {

    employeeRepository.deleteAll();
    Employee employee = new Employee("3y", 23);

    // 模拟异常
    int i = 1 / 0;

    return employee;
}

我第一直覺是:這跟Spring事務的傳播機制有關吧。

其實這跟Spring事務的傳播機制沒有關係,下面我講述一下:

  • Spring事務管理用的是AOP,AOP底層用的是動態代理。所以如果我們在類別或方法上標註註解@Transactional,那麼會產生一個代理物件

接下來我用圖來說明:

Spring事務的深入解析(附範例)

显然地,我们拿到的是代理(Proxy)对象,调用addEmployee2Controller()方法,而addEmployee2Controller()方法的逻辑是target.addEmployee(),调用回原始对象(target)的addEmployee()。所以这次的调用压根就没有事务存在,更谈不上说Spring事务传播机制了。

Spring事務的深入解析(附範例):

Spring事務的深入解析(附範例)

测试结果:压根就Spring事務的深入解析(附範例)

Spring事務的深入解析(附範例)

2.2.1再延伸一下

从上面的测试我们可以发现:如果是在本类中没有事务的方法来调用标注注解@Transactional方法,最后的结论是没有事务的。那如果我将这个标注注解的方法移到别的Service对象上,有没有事务?

@Service
public class TestService {

    @Autowired
    private EmployeeRepository employeeRepository;
    
    @Transactional
    public Employee addEmployee() throws Exception {

        employeeRepository.deleteAll();

        Employee employee = new Employee("3y", 23);

        // 模拟异常
        int i = 1 / 0;

        return employee;
    }

}


@Service
public class EmployeeService {

    @Autowired
    private TestService testService;
    // 没有事务的方法去调用别的类有事务的方法
    public Employee addEmployee2Controller() throws Exception {
        return testService.addEmployee();
    }
}

测试结果:

Spring事務的深入解析(附範例)

因为我们用的是代理对象(Proxy)去调用addEmployee()方法,那就当然有事务了。

看完这两个例子,有没有觉得3y的直觉是真的水

三、Spring事务传播机制

如果嵌套调用含有事务的方法,在Spring事务管理中,这属于哪个知识点?

在当前含有事务方法内部调用其他的方法(无论该方法是否含有事务),这就属于Spring事务传播机制的知识点范畴了。

Spring事务基于Spring AOP,Spring AOP底层用的动态代理,动态代理有两种方式:

  • 基于接口代理(JDK代理)

    • 基于接口代理,凡是类的方法非public修饰,或者用了static关键字修饰,那这些方法都不能被Spring AOP增强

  • 基于CGLib代理(子类代理)

    • 基于子类代理,凡是类的方法使用了private、static、final修饰,那这些方法都不能被Spring AOP增强

至于为啥以上的情况不能增强,用你们的脑瓜子想一下就知道了。

值得说明的是:那些不能被Spring AOP增强的方法并不是不能在事务环境下工作了。只要它们被外层的事务方法调用了,由于Spring事务管理的传播级别,内部方法也可以工作在外部方法所启动的事务上下文中

至于Spring事务传播机制的几个级别,我在这里就不贴出来了。这里只是再次解释“啥情况才是属于Spring事务传播机制的范畴”。

四、多线程问题

我们使用的框架可能是Hibernate/JPA或者是Mybatis,都知道的底层是需要一个session/connection对象来帮我们执行操作的。要保证事务的完整性,我们需要多组数据库操作要使用同一个session/connection对象,而我们又知道Spring IOC所管理的对象默认都是单例的,这为啥我们在使用的时候不会引发线程安全问题呢?内部Spring到底干了什么?

回想一下当年我们学Mybaits的时候,是怎么编写Session工具类?

Spring事務的深入解析(附範例)

没错,用的就是ThreadLocal,同样地,Spring也是用的ThreadLocal。

以下内容来源《精通 Spring4.x》

我们知道在一般情况下,只有无状态的Bean才可以在多线程环境下共享,在Spring中,绝大部分Bean都可以声明为singleton作用域。就是因为Spring对一些Bean(如RequestContextHolder、TransactionSynchronizationManager、LocaleContextHolder等)中非线程安全状态的“状态性对象”采用ThreadLocal封装,让它们也成为线程安全的“状态性对象”,因此,有状态的Bean就能够以singleton的方式在多线程中工作。

我们可以试着点一下进去TransactionSynchronizationManager中看一下:

Spring事務的深入解析(附範例)

五、啥是BPP?

BBP的全名為:BeanPostProcessor,一般我們俗稱物件後處理器

  • 簡單來說,透過BeanPostProcessor可以對我們的物件進行“加工處理”。

Spring管理Bean(或說Bean的生命週期)也是一個常考的知識點,我在秋招也重新整理了一下步驟,因為比較重要,所以還是在這裡貼一下吧:

  1. ResouceLoader加載配置信息

  2. BeanDefintionReader解析配置信息,生成一個一個的BeanDefintion

  3. BeanDefintion由BeanDefintionRegistry管理起來

  4. ##BeanFactoryPostProcessor對設定資訊進行加工(也就是處理配置的信息,一般透過處理配置的信息,一般透過處理配置的信息,一般透過處理配置的信息來實作)

  5. 實例化Bean

  6. #如果該Bean

    設定/實作了InstantiationAwareBean,則呼叫對應的方法

  7. 使用BeanWarpper來完成物件之間的屬性配置(依賴)

  8. 如果該Bean

    配置/實作了 Aware接口,則呼叫對應的方法

  9. 如果該Bean配置了BeanPostProcessor的before方法,則呼叫

  10. 如果該Bean配置了

    init-method或實作InstantiationBean,則呼叫對應的方法

  11. #如果該Bean配置了BeanPostProcessor的after方法,則呼叫

  12. #將物件放入到HashMap中

  13. 最後如果配置了destroy或DisposableBean的方法,則執行銷毀操作

Spring事務的深入解析(附範例)

其中也有關於BPP圖:

Spring事務的深入解析(附範例)

#5.1為什麼要特意講BPP?

Spring AOP程式設計底層通過的是動態代理技術,在呼叫的時候肯定用的是

代理物件。那麼Spring是怎麼做的呢?

我只需要寫一個BPP,在postProcessBeforeInitialization或postProcessAfterInitialization方法中,對物件進行判斷,看他需不需要織入切面邏輯,如果需要,那我就根據這個對象,生成一個代理對象,然後返回這個代理對象,那麼最終注入容器的,自然就是代理對象了。

Spring提供了BeanPostProcessor,就是讓我們可以對有需要的物件進行「

加工處理」啊!

六、認識Spring事務幾個重要的介面

Spring交易可以分為兩種:

  • 編程式事務(透過程式碼的方式來實作事務)

  • 聲明式交易(透過配置的方式來實作交易)

編排事務在Spring實作相對簡單一些,而宣告式事務因為封裝了大量的東西(一般我們使用簡單,裡頭都非常複雜),所以聲明式事務實作要難得多。

在編程式交易中有以下幾個重要的了介面:

  • TransactionDefinition:定義了Spring相容的

    交易屬性(例如事務隔離等級、事務傳播、交易逾時、是否唯讀狀態)

  • TransactionStatus:代表了事務的具體

    運行狀態(獲取事務運行狀態的信息,也可以透過此介面間接回溯事務等操作)

  • PlatformTransactionManager:事務管理器介面(定義了一組行為,具體實作交由不同的持久化框架來完成---

    類比JDBC)

Spring事務的深入解析(附範例)

在聲明式事務中,除了TransactionStatus和PlatformTransactionManager接口,還有幾個重要的介面:

  • TransactionProxyFactoryBean:產生代理物件

  • TransactionInterceptor:實作物件的攔截

  • #TransactionAttrubute:事務配置的資料

  • #

以上是Spring事務的深入解析(附範例)的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述
本文轉載於:博客园。如有侵權,請聯絡admin@php.cn刪除
如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

如何在Java中實施功能編程技術?如何在Java中實施功能編程技術?Mar 11, 2025 pm 05:51 PM

本文使用lambda表達式,流API,方法參考和可選探索將功能編程集成到Java中。 它突出顯示了通過簡潔性和不變性改善代碼可讀性和可維護性等好處

Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

如何將Java的Nio(新輸入/輸出)API用於非阻滯I/O?如何將Java的Nio(新輸入/輸出)API用於非阻滯I/O?Mar 11, 2025 pm 05:51 PM

本文使用選擇器和頻道使用單個線程有效地處理多個連接的Java的NIO API,用於非阻滯I/O。 它詳細介紹了過程,好處(可伸縮性,性能)和潛在的陷阱(複雜性,

如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

如何使用Java的插座API進行網絡通信?如何使用Java的插座API進行網絡通信?Mar 11, 2025 pm 05:53 PM

本文詳細介紹了用於網絡通信的Java的套接字API,涵蓋了客戶服務器設置,數據處理和關鍵考慮因素,例如資源管理,錯誤處理和安全性。 它還探索了性能優化技術,我

See all articles

熱AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover

AI Clothes Remover

用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool

Undress AI Tool

免費脫衣圖片

Clothoff.io

Clothoff.io

AI脫衣器

AI Hentai Generator

AI Hentai Generator

免費產生 AI 無盡。

熱門文章

R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.最佳圖形設置
3 週前By尊渡假赌尊渡假赌尊渡假赌
R.E.P.O.如果您聽不到任何人,如何修復音頻
3 週前By尊渡假赌尊渡假赌尊渡假赌

熱工具

SublimeText3漢化版

SublimeText3漢化版

中文版,非常好用

MinGW - Minimalist GNU for Windows

MinGW - Minimalist GNU for Windows

這個專案正在遷移到osdn.net/projects/mingw的過程中,你可以繼續在那裡關注我們。 MinGW:GNU編譯器集合(GCC)的本機Windows移植版本,可自由分發的導入函式庫和用於建置本機Windows應用程式的頭檔;包括對MSVC執行時間的擴展,以支援C99功能。 MinGW的所有軟體都可以在64位元Windows平台上運作。

Atom編輯器mac版下載

Atom編輯器mac版下載

最受歡迎的的開源編輯器

記事本++7.3.1

記事本++7.3.1

好用且免費的程式碼編輯器

mPDF

mPDF

mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),