1. 程式人生 > >手把手帶你實戰下Spring的七種事務傳播行為

手把手帶你實戰下Spring的七種事務傳播行為

目錄

  • 一、什麼是事務傳播行為?
  • 二、事務的7種傳播行為
  • 三、7種傳播行為實戰

本文介紹Spring的七種事務傳播行為並通過程式碼演示下。

一、什麼是事務傳播行為?

事務傳播行為(propagation behavior)指的就是當一個事務方法被另一個事務方法呼叫時,這個事務方法應該如何執行。

例如:methodA方法呼叫methodB方法時,methodB是繼續在呼叫者methodA的事務中執行呢,還是為自己開啟一個新事務執行,這就是由methodB的事務傳播行為決定的。

二、事務的7種傳播行為

Spring在TransactionDefinition介面中規定了7種類型的事務傳播行為。事務傳播行為是Spring框架獨有的事務增強特性。這是Spring為我們提供的強大的工具箱,使用事務傳播行為可以為我們的開發工作提供許多便利。

7種事務傳播行為如下:

1.PROPAGATION_REQUIRED

如果當前沒有事務,就建立一個新事務,如果當前存在事務,就加入該事務,這是最常見的選擇,也是Spring預設的事務傳播行為。

2.PROPAGATION_SUPPORTS

支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。

3.PROPAGATION_MANDATORY

支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就丟擲異常。

4.PROPAGATION_REQUIRES_NEW

建立新事務,無論當前存不存在事務,都建立新事務。

5.PROPAGATION_NOT_SUPPORTED

以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

6.PROPAGATION_NEVER

以非事務方式執行,如果當前存在事務,則丟擲異常。

7.PROPAGATION_NESTED

如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則按REQUIRED屬性執行。

其實這7中我也沒看懂,不過不急,咱們接下來直接看效果。

三、7種傳播行為實戰

演示前先建兩個表,使用者表和使用者角色表,一開始兩個表裡沒有資料。

需要注意下,為了資料更直觀,每次執行程式碼時 先清空下user和user_role表的資料。

user表:

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(255) DEFAULT NULL,
  `password` varchar(255) DEFAULT NULL,
  `sex` int(11) DEFAULT NULL,
  `des` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

user_role表:

CREATE TABLE `user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(11) DEFAULT NULL,
  `role_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;

1.PROPAGATION_REQUIRED測試

如果當前沒有事務,就建立一個新事務,如果當前存在事務,就加入該事務,這是最常見的選擇,也是Spring預設的事務傳播行為。

場景一:

此場景外圍方法沒有開啟事務。

1.驗證方法

兩個實現類UserServiceImpl和UserRoleServiceImpl制定事物傳播行為propagation=Propagation.REQUIRED,然後在測試方法中同時呼叫兩個方法並在呼叫結束後丟擲異常。

2.主要程式碼

外層呼叫方法程式碼:

/**
     * 測試 PROPAGATION_REQUIRED
     *
     * @Author: java_suisui
     */
    @Test
    void test_PROPAGATION_REQUIRED() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

UserServiceImpl程式碼:

/**
     * 增加使用者
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int add(User user) {
        return userMapper.add(user);
    }

UserRoleServiceImpl程式碼:

    /**
     * 增加使用者角色
     */
    @Transactional(propagation = Propagation.REQUIRED)
    @Override
    public int add(UserRole userRole) {
        return userRoleMapper.add(userRole);
    }

3.程式碼執行後資料庫截圖

兩張表資料都新增成功,截圖如下:

4.結果分析

外圍方法未開啟事務,插入使用者表和使用者角色表的方法在自己的事務中獨立執行,外圍方法異常不影響內部插入,所以兩條記錄都新增成功。

場景二:

此場景外圍方法開啟事務。

1.主要程式碼

測試方法程式碼如下:

/**
     * 測試 PROPAGATION_REQUIRED
     *
     * @Author: java_suisui
     */
    @Transactional
    @Test
    void test_PROPAGATION_REQUIRED() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

2.程式碼執行後資料庫截圖

兩張表資料都為空,截圖如下:

3.結果分析

外圍方法開啟事務,內部方法加入外圍方法事務,外圍方法回滾,內部方法也要回滾,所以兩個記錄都插入失敗。

結論:以上結果證明在外圍方法開啟事務的情況下Propagation.REQUIRED修飾的內部方法會加入到外圍方法的事務中,所以Propagation.REQUIRED修飾的內部方法和外圍方法均屬於同一事務,只要一個方法回滾,整個事務均回滾。

2.PROPAGATION_SUPPORTS測試

支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。

場景一:

此場景外圍方法沒有開啟事務。

1.驗證方法

兩個實現類UserServiceImpl和UserRoleServiceImpl制定事物傳播行為propagation=Propagation.SUPPORTS,然後在測試方法中同時呼叫兩個方法並在呼叫結束後丟擲異常。

2.主要程式碼

外層呼叫方法程式碼:

    /**
     * 測試 PROPAGATION_SUPPORTS
     *
     * @Author: java_suisui
     */
    @Test
    void test_PROPAGATION_SUPPORTS() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

UserServiceImpl程式碼:

/**
     * 增加使用者
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public int add(User user) {
        return userMapper.add(user);
    }

UserRoleServiceImpl程式碼:

    /**
     * 增加使用者角色
     */
    @Transactional(propagation = Propagation.SUPPORTS)
    @Override
    public int add(UserRole userRole) {
        return userRoleMapper.add(userRole);
    }

3.程式碼執行後資料庫截圖

兩張表資料都新增成功,截圖如下:

4.結果分析

外圍方法未開啟事務,插入使用者表和使用者角色表的方法以非事務的方式獨立執行,外圍方法異常不影響內部插入,所以兩條記錄都新增成功。

場景二:

此場景外圍方法開啟事務。

1.主要程式碼

test_PROPAGATION_SUPPORTS方法添加註解@Transactional即可。

2.程式碼執行後資料庫截圖

兩張表資料都為空,截圖如下:

3.結果分析

外圍方法開啟事務,內部方法加入外圍方法事務,外圍方法回滾,內部方法也要回滾,所以兩個記錄都插入失敗。

結論:以上結果證明在外圍方法開啟事務的情況下Propagation.SUPPORTS修飾的內部方法會加入到外圍方法的事務中,所以Propagation.SUPPORTS修飾的內部方法和外圍方法均屬於同一事務,只要一個方法回滾,整個事務均回滾。

3.PROPAGATION_MANDATORY測試

支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就丟擲異常。

通過上面的測試,“支援當前事務,如果當前存在事務,就加入該事務”,這句話已經驗證了,外層新增@Transactional註解後兩條記錄都新增失敗,所以這個傳播行為只測試下外層沒有開始事務的場景。

場景一:

此場景外圍方法沒有開啟事務。

1.驗證方法

兩個實現類UserServiceImpl和UserRoleServiceImpl制定事物傳播行為propagation = Propagation.MANDATORY,主要程式碼如下。

2.主要程式碼

外層呼叫方法程式碼:

    /**
     * 測試 PROPAGATION_MANDATORY
     *
     * @Author: java_suisui
     */
    @Test
    void test_PROPAGATION_MANDATORY() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

UserServiceImpl程式碼:

/**
     * 增加使用者
     */
    @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public int add(User user) {
        return userMapper.add(user);
    }

UserRoleServiceImpl程式碼:

    /**
     * 增加使用者角色
     */
    @Transactional(propagation = Propagation.MANDATORY)
    @Override
    public int add(UserRole userRole) {
        return userRoleMapper.add(userRole);
    }

3.程式碼執行後資料庫截圖

兩張表資料都為空,截圖如下:

4.結果分析

執行日誌如下,可以發現在呼叫userService.add()時候已經報錯了,所以兩個表都沒有新增資料,驗證了“如果當前不存在事務,就丟擲異常”。

at com.example.springboot.mybatisannotation.service.impl.UserServiceImpl$$EnhancerBySpringCGLIB$$50090f18.add(<generated>)
    at com.example.springboot.mybatisannotation.SpringBootMybatisAnnotationApplicationTests.test_PROPAGATION_MANDATORY(SpringBootMybatisAnnotationApplicationTests.java:78)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)

4.PROPAGATION_REQUIRES_NEW測試

建立新事務,無論當前存不存在事務,都建立新事務。

這種情況每次都建立事務,所以我們驗證一種情況即可。

場景一:

此場景外圍方法開啟事務。

1.驗證方法

兩個實現類UserServiceImpl和UserRoleServiceImpl制定事物傳播行為propagation = Propagation.REQUIRES_NEW,主要程式碼如下。

2.主要程式碼

外層呼叫方法程式碼:

    /**
     * 測試 REQUIRES_NEW
     *
     * @Author: java_suisui
     */
    @Test
    @Transactional
    void test_REQUIRES_NEW() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

UserServiceImpl程式碼:

/**
     * 增加使用者
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public int add(User user) {
        return userMapper.add(user);
    }

UserRoleServiceImpl程式碼:

    /**
     * 增加使用者角色
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    @Override
    public int add(UserRole userRole) {
        return userRoleMapper.add(userRole);
    }

3.程式碼執行後資料庫截圖

兩張表資料都新增成功,截圖如下:

4.結果分析

無論當前存不存在事務,都建立新事務,所以兩個資料新增成功。

5.PROPAGATION_NOT_SUPPORTED測試

以非事務方式執行操作,如果當前存在事務,就把當前事務掛起。

場景一:

此場景外圍方法不開啟事務。

1.驗證方法

兩個實現類UserServiceImpl和UserRoleServiceImpl制定事物傳播行為propagation = Propagation.NOT_SUPPORTED,主要程式碼如下。

2.主要程式碼

外層呼叫方法程式碼:

    /**
     * 測試 PROPAGATION_NOT_SUPPORTED
     *
     * @Author: java_suisui
     */
    @Test
    void test_PROPAGATION_NOT_SUPPORTED() {
        // 增加使用者表
        User user = new User();
        user.setName("Java碎碎念");
        user.setPassword("123456");
        userService.add(user);
        // 增加使用者角色表
        UserRole userRole = new UserRole();
        userRole.setUserId(user.getId());
        userRole.setRoleId(200);
        userRoleService.add(userRole);
        //拋異常
        throw new RuntimeException();
    }

UserServiceImpl程式碼:

/**
     * 增加使用者
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public int add(User user) {
        return userMapper.add(user);
    }

UserRoleServiceImpl程式碼:

    /**
     * 增加使用者角色
     */
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    @Override
    public int add(UserRole userRole) {
        return userRoleMapper.add(userRole);
    }

3.程式碼執行後資料庫截圖

兩張表資料都新增成功,截圖如下:

4.結果分析

以非事務方式執行,所以兩個資料新增成功。

場景二:

此場景外圍方法開啟事務。

1.主要程式碼

test_PROPAGATION_NOT_SUPPORTED方法添加註解@Transactional即可。

2.程式碼執行後資料庫截圖

兩張表資料都新增成功,截圖如下:

3.結果分析

如果當前存在事務,就把當前事務掛起,相當於以非事務方式執行,所以兩個資料新增成功。

6.PROPAGATION_NEVER測試

以非事務方式執行,如果當前存在事務,則丟擲異常。

上面已經有類似情況,外層沒有事務會以非事務的方式執行,兩個表新增成功;有事務則丟擲異常,兩個表都都沒有新增資料。

7.PROPAGATION_NESTED測試

如果當前存在事務,則在巢狀事務內執行。如果當前沒有事務,則按REQUIRED屬性執行。

上面已經有類似情況,外層沒有事務會以REQUIRED屬性的方式執行,兩個表新增成功;有事務但是用的是一個事務,方法最後丟擲了異常導致回滾,兩個表都都沒有新增資料。

到此Spring的7種事務傳播行為已經全部介紹完成了,有問題歡迎留言溝通哦!

完整原始碼地址: https://github.com/suisui2019/springboot-study

推薦閱讀

1.SpringBoot系列-整合Mybatis(註解方式)
2.SpringBoot系列-整合Mybatis(XML配置方式)
3.Java中列印日誌,這4點很重要!
4.SpringBoot整合JWT實現許可權認證
5.一分鐘帶你瞭解JWT認證!


限時領取免費Java相關資料,涵蓋了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo/Kafka、Hadoop、Hbase、Flink等高併發分散式、大資料、機器學習等技術。
關注下方公眾號即可免費領取:

相關推薦

手把手實戰Spring事務傳播行為

目錄 一、什麼是事務傳播行為? 二、事務的7種傳播行為 三、7種傳播行為實戰 本文介紹Spring的七種事務傳播行為並通過程式碼演示下。 一、什麼是事務傳播行為? 事務傳播行為(propag

spring 事務傳播行為和五事務隔離級別

事務傳播行為:propagation_控制事務傳播行為 1.REQUIRED(預設值):如果當前有事務,就在事務中執行;如果沒有事務,就新建一個事務 2.SUPPORTS:如果當前有事務,就在事務中執行;如果沒有事務,就在非事務狀態下執行 3.MANDATORY:必須在

spring事務(Transaction)的事務傳播行為及五隔離級別

1. 首先,說說什麼事務(Transaction) 事務,就是一組操作資料庫的動作集合。事務是現代資料庫理論中的核心概念之一。 如果一組處理步驟或者全部發生或者一步也不執行,我們稱該組處理步驟為一個事務。 當所有的步驟像一個操作一樣被完整地執行,我們稱該事務被

一分鐘瞭解Spring Security!

一、什麼是Spring Security? Spring Security是一個功能強大且高度可定製的身份驗證和訪問控制框架,它是用於保護基於Spring的應用程式的實際標準。 Spring Security是一個框架,致力於為Java應用程式提供身份驗證和授權。與所有Spring專案一樣,Spring Se

Spring事務傳播機制

詳細 class support 繼續 tar 傳播行為 類型 情況 隔離 概述 當我們調用一個基於Spring的Service接口方法(如UserService#addUser())時,它將運行於Spring管理的事務環境中,Service接口方法可能會在內部調用其它的S

Spring事務的四特性 事務的三併發訪問問題真實場景解讀 事務的四隔離級別 事務傳播行為

1.事務的基本特性(ACID) 原子性:一個事務是一個整體,不可分割,事務中的操作要麼全部成功要麼全部失敗 一致性:一致性和原子性描述的是同一件事情,原子性是從操作的角度來說,要麼全部成功要麼全部失敗,一致性是從資料的角度來說,資料要麼是事務提交前的狀態,要麼是事務全部完成的狀態.比

Spring.NET教程(十事務傳播行為(基礎篇)

上篇我們學習了Spring.net的事務機制。回顧一下,實現事務需要在方法上標記[Transaction]。在很多情況下,事務往往與業務分離。Spring.NET提供了事務代理幫我們管理這些事務,我們可以通過TransactionProxyFactoryObject使用宣告式事務。在很多情況下Transact

Spring的7事務傳播行為型別

1、PROPAGATION_REQUIRED:如果當前沒有事務,就建立一個新事務,如果當前存在事務,就加入該事務,該設定是最常用的設定。 2、PROPAGATION_SUPPORTS:支援當前事務,如果當前存在事務,就加入該事務,如果當前不存在事務,就以非事務執行。‘ 3、

Spring事務傳播屬性

PROPAGATION_REQUIRED -- 支援當前事務,如果當前沒有事務,就新建一個事務。這是最常見的選擇。PROPAGATION_SUPPORTS -- 支援當前事務,如果當前沒有事務,就以非事務方式執行。PROPAGATION_MANDATORY -- 支援當前事務,如果當前沒有事務,就丟擲異常。P

PROPAGATION_REQUIRED及其他6事務傳播行為種類

<!-- 定義事務攔截器bean--> <bean id="transactionInterceptor"    class="org.springframework.transaction.interceptor.TransactionInterceptor">    <!--

Spring7事務傳播行為型別

事務傳播行為種類 Spring在TransactionDefinition介面中規定了7種類型的事務傳播行為, 它們規定了事務方法和事務方法發生巢狀呼叫時事務如何進行傳播: 事務傳播行為型別 事務傳播行為型別 說明 PROPAGATION_REQUIRED 如

Spring無效的事務傳播行為

insertRole方法上的propagation=Propagation.REQUIRES_NEW表示不管當前上下文環境有沒有事務,都重新開啟一個新的事務,但實際上是不生效的。原因如下:Spring的事務管理是在通過動態代理類進入invoke方法裡面的,然後判斷是否需要攔截

別怕,手把手撕、拉、扯SpringMVC的外衣

ons mvc springmvc test stp 實的 per war sdi 提到框架,就不得不提一下看源碼,我們平時總是想求大神帶我們飛,然而看源碼就是一個向大神學習的最直接的一種方式,然而我們每次鼓起勇氣看源碼前是這樣的但是一點開源碼,頓時代碼如洪流湧入,你的內心

從基礎到實戰 手把手掌握新版Webpack4.0

開發環境 entry 輸出 第5章 配置文件 衍生 vid dex 學會 原文配套視頻資源獲取鏈接:點擊獲取 原文配套源碼資源獲取鏈接:點擊獲取 第1章 課程導學(打消你的學習疑慮) 掌握Webpack越來越成為前端工程師的標配技能,本章會對課程整體進行介

手把手入門 Spring Security!

Spring Security 是 Spring 家族中的一個安全管理框架,實際上,在 Spring Boot 出現之前,Spring Security 就已經發展了多年了,但是使用的並不多,安全管理這個領域,一直是 Shiro 的天下。 相對於 Shiro,在 SSM/SSH 中整合 Spring Sec

應該掌握的回歸技術

adjust 之間 給定 了解 我會 關系圖 log 目的 new 轉自:http://www.iteye.com/news/30875 英文原文:https://www.analyticsvidhya.com/blog/2015/08/comprehensive-guid

手把手畫一個 時尚儀表盤 Android 自己定義View

androi alias 屬性 extend 三角函數 blank xutils content 還在 拿到美工效果圖。咱們程序猿就得畫得一模一樣。 為了不被老板噴,僅僅能多練啊。 聽說你認為前面幾篇都so easy,那今天就帶你做個相對照較復雜的。

Android性能優化:手把手全面了解 內存泄露 & 解決方案

new t 簡單介紹 新建 cti 接口 stat you bit ray . 簡介 即 ML (Memory Leak)指 程序在申請內存後,當該內存不需再使用 但 卻無法被釋放 & 歸還給 程序的現象2. 對應用程序的影響 容易使得應用程序發生內存溢出,即 OO

手把手入坑H5與小程序直播開發視頻課程直播的工作原理教程

直播 H5 微信 第1章 課程介紹對於課程整體以及直播行業的現狀進行介紹第2章 直播工作原理所謂知其然也要知其所以然,只會用別人總結好的東西很難有質的進步,只有深諳背後的工作原理才能進一步吃透到進階。本章從直播協議入手到工作原理詳解,步步為營,化繁為簡,極易吸收。第3章 Video詳解video

小編了解Spring Cloud 微服務

做到 隨著 減少 工具包 註冊 其它 系統開發 onf 數據 Spring Cloud 簡介    Spring Cloud是一系列框架的有序集合。它利用Spring Boot的開發便利性巧妙地簡化了分布式系統基礎設施的開發,如服務發現註冊、配置中心、消息總線、負載均衡、斷