欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中Spring對事務的支持詳解

 更新時間:2023年07月11日 11:04:08   作者:藍云飄飄2366  
這篇文章主要介紹了Java中Spring對事務的支持詳解,Spring對事務的支持有兩種方式,一是自己編寫事務,精確控制事務的邊界,二是采用聲明事務的方式,使用AOP來完成,需要的朋友可以參考下

事務屬性

  • 事務傳播行為;--Propagation(本文重點解讀事務傳播行為)
  • 事務隔離級別;--Isolation
  • 事務超時;--timeout
  • 只讀事務;--readOnly
  • 設置出現(xiàn)哪些異?;貪L事務;--rollbackFor
  • 設置出現(xiàn)哪些異常不回滾事務;--noRollbackFor

事務的傳播行為

一、什么是事務的傳播行為

在service類中有a()方法和b()方法,a()方法上有事務,b()方法上也有事務,當a()方法執(zhí)行過程中調用了b()方法,事務是如何傳遞的?合并到一個事務里?還是開啟一個新的事務?這就是事務傳播行為。

注意:以下事務傳播屬性都是打在內部方法b()方法上的事務注解

二、7種事務傳播行為

Spring 可以通過 @Transactional 注解的 propagation 屬性來設置不同的傳播行為策略。

Spring 為此提供了一個枚舉類 Propagation,源碼如下:

package org.springframework.transaction.annotation;
import org.springframework.transaction.TransactionDefinition;
public enum Propagation {
   /**
    * 需要事務,它是默認傳播行為,如果當前存在事務,就沿用當前事務,
    * 否則新建一個事務運行內部方法
    */
   REQUIRED(TransactionDefinition.PROPAGATION_REQUIRED),
   /**
    * 支持事務,如果當前存在事務,就沿用當前事務,
    * 如果不存在,則繼續(xù)采用無事務的方式運行內部方法
    */
   SUPPORTS(TransactionDefinition.PROPAGATION_SUPPORTS),
   /**
    * 必須使用事務,如果當前沒有事務,則會拋出異常,
    * 如果存在當前事務,則沿用當前事務
    */
   MANDATORY(TransactionDefinition.PROPAGATION_MANDATORY),
   /**
    * 無論當前事務是否存在,都會創(chuàng)建新事務運行方法,
    * 這樣新事務就可以擁有新的鎖和隔離級別等特性,與當前事務相互獨立
    */
   REQUIRES_NEW(TransactionDefinition.PROPAGATION_REQUIRES_NEW),
   /**
    * 不支持事務,當前存在事務時,將掛起事務,運行方法
    */
   NOT_SUPPORTED(TransactionDefinition.PROPAGATION_NOT_SUPPORTED),
   /**
    * 不支持事務,如果當前方法存在事務,則拋出異常,否則繼續(xù)使用無事務機制運行
    */
   NEVER(TransactionDefinition.PROPAGATION_NEVER),
   /**
    * 在當前方法調用內部方法時,如果內部方法發(fā)生異常,
    * 只回滾內部方法執(zhí)行過的 SQL ,而不回滾當前方法的事務
    */
   NESTED(TransactionDefinition.PROPAGATION_NESTED);
......
}

接下來我們通過對其中三種最常用的(REQUIRED、REQUIRES_NEW、NESTED)策略進行對比來更深入的理解。以下測試均在外部方法開啟事務的情況下進行,因為在外部沒有事務的情況下,三者都會新建事務,效果一樣。 

1. REQUIRED

當內部方法的事務傳播行為設置為 REQUIRED 時,內部方法會加入外部方法的事務。我們在 UserServiceImpl 中添加如下方法:  

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
   @Autowired
   private UserMapper mapper;
   @Override
   @Transactional(propagation = Propagation.REQUIRED)
   public void addWithRequired(User user) {
       mapper.insert(user);
  }
   @Override
   @Transactional(propagation = Propagation.REQUIRED)
   public void addWithRequiredAndException(User user) {
       mapper.insert(user);
       throw new RuntimeException();
  }
}

創(chuàng)建 TransactionServiceImpl 類,并添加如下方法:

@Slf4j
@Service
public class TransactionServiceImpl implements TransactionService {
    @Autowired
    private UserService userService;
    @Override
    public void noTransaction_required_required_externalException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequired(xiaoJing);
        throw new RuntimeException();
    }
    @Override
    public void noTransaction_required_requiredException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequiredAndException(xiaoJing);
    }
    @Override
    @Transactional
    public void transaction_required_required_externalException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequired(xiaoJing);
        throw new RuntimeException();
    }
    @Override
    @Transactional
    public void transaction_required_requiredException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequiredAndException(xiaoJing);
    }
    @Override
    @Transactional
    public void transaction_required_requiredException_try() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        try {
            userService.addWithRequiredAndException(xiaoJing);
        } catch (Exception e) {
            log.error("發(fā)生異常,事務回滾!");
        }
    }
}

結果分析如下表所示:

前面四種情況都比較好理解,很多人不能理解最后一種情況:我都 try-catch 了你還想怎樣?這里的關鍵點在于所有方法都處于同一個事務中,此時「小鏡」的插入方法發(fā)生異常,那么這個方法所在的事務就會被 Spring 設置為 rollback 狀態(tài)。因為異常被 catch 了,所以外部方法執(zhí)行完要進行 commit 操作,這時卻發(fā)現(xiàn)當前事務已經處于 rollback 狀態(tài)了,雖然它不知道哪里出了問題,但也只能聽從指揮,回滾所有操作了。

PS:由于外部方法不開啟事務的情況,在每種傳播行為下結果都是類似的,所以后面不再給出示例。

2. REQUIRES_NEW

當內部方法的傳播行為設置為 REQUIRES_NEW 時,內部方法會先將外部方法的事務掛起,然后開啟一個新的事務 。在 UserServiceImpl 中添加如下方法(UserServiceImpl 類中上面的方法還在哦):

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    ...
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addWithRequiredNew(User user) {
        mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void addWithRequiredNewAndException(User user) {
        mapper.insert(user);
        throw new RuntimeException();
    }
}

在 TransactionServiceImpl 中添加如下方法:

@Slf4j
@Service
public class TransactionServiceImpl implements TransactionService {
    ...
    @Override
    @Transactional
    public void transaction_required_requiredNew_externalException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequiredNew(xiaoJing);
        throw new RuntimeException();
    }
    @Override
    @Transactional
    public void transaction_required_requiredNew_requiredNewException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        User shuiJing = new User().setName("水鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequiredNew(xiaoJing);
        userService.addWithRequiredNewAndException(shuiJing);
    }
    @Override
    @Transactional
    public void transaction_required_requiredNewException_try() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        User shuiJing = new User().setName("水鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithRequiredNew(xiaoJing);
        try {
            userService.addWithRequiredNewAndException(shuiJing);
        } catch (Exception e) {
            log.error("發(fā)生異常,事務回滾!");
        }
    }
}

結果分析如下表所示:

3. NESTED

當內部方法的傳播行為設置為 NESTED 時,內部方法會開啟一個新的嵌套事務(子事務)。在 UserServiceImpl 中添加如下方法:

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
    ...
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addWithNested(User user) {
        mapper.insert(user);
    }
    @Override
    @Transactional(propagation = Propagation.NESTED)
    public void addWithNestedAndException(User user) {
        mapper.insert(user);
        throw new RuntimeException();
    }
}

在 TransactionServiceImpl 中添加如下方法:  

@Slf4j
@Service
public class TransactionServiceImpl implements TransactionService {
    ...
    @Override
    @Transactional
    public void transaction_nested_nested_externalException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithNested(xiaoShui);
        userService.addWithNested(xiaoJing);
        throw new RuntimeException();
    }
    @Override
    @Transactional
    public void transaction_nested_nestedException() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        userService.addWithNested(xiaoShui);
        userService.addWithNestedAndException(xiaoJing);
    }
    @Override
    @Transactional
    public void transaction_nested_nestedException_try() {
        User xiaoShui = new User().setName("小水");
        User xiaoJing = new User().setName("小鏡");
        User shuiJing = new User().setName("水鏡");
        userService.addWithRequired(xiaoShui);
        userService.addWithNested(xiaoJing);
        try {
            userService.addWithNestedAndException(shuiJing);
        } catch (Exception e) {
            log.error("發(fā)生異常,事務回滾!",e);
        }
    }
}

結果分析如下表所示:

每個 NESTED 事務執(zhí)行前會將當前操作保存下來,叫做 savepoint (保存點),如果當前 NESTED 事務執(zhí)行失敗,則回滾到之前的保存點,保存點使得子事務的回滾不對主事務造成影響。NESTED 事務在外部事務提交以后自己才會提交。

4. 總結

REQUIRES_NEW 最為簡單,不管當前有無事務,它都會開啟一個全新事務,既不影響外部事務,也不會影響其他內部事務,真正的井水不犯河水,堅定而獨立。

REQUIRED 在沒有外部事務的情況下,會開啟一個獨立的新事務,且不會對其他同級事務造成影響;而當存在外部事務的情況下,則會與外部事務同生共死。

NESTED 在沒有外部事務的情況下與 REQUIRED 效果相同;而當存在外部事務的情況下,當外部事務回滾時,它會創(chuàng)建一個嵌套事務(子事務)。外部事務回滾時,子事務會跟著回滾;但子事務的回滾不會對外部事務和其他同級事務造成影響。

三、事務的傳播行為(理解記憶)

到此這篇關于Java中Spring對事務的支持詳解的文章就介紹到這了,更多相關Spring對事務的支持內容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

  • SpringBoot實現(xiàn)動態(tài)數據源切換的方法總結

    SpringBoot實現(xiàn)動態(tài)數據源切換的方法總結

    項目開發(fā)中經常會遇到多數據源同時使用的場景,比如冷熱數據的查詢等情況,所以接下來本文就來介紹一下如何使用實現(xiàn)自定義注解的形式來實現(xiàn)動態(tài)數據源切換吧
    2023-12-12
  • java Tcp通信客戶端與服務器端實例

    java Tcp通信客戶端與服務器端實例

    這篇文章主要介紹了java Tcp通信客戶端與服務器端,結合完整實例形式詳細分析了java基于tcp的網絡通信客戶端與服務器端具體實現(xiàn)技巧,需要的朋友可以參考下
    2020-01-01
  • java項目實現(xiàn)統(tǒng)一打印入參出參等日志

    java項目實現(xiàn)統(tǒng)一打印入參出參等日志

    這篇文章主要介紹了java項目實現(xiàn)統(tǒng)一打印入參出參等日志方式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2023-03-03
  • Java服務cpu100%的解決過程分享

    Java服務cpu100%的解決過程分享

    最近一個任務是優(yōu)化一個導出的功能,但是點擊功能時發(fā)現(xiàn),程序長時間無反應,過一段時間又有反應,通過查看服務的監(jiān)控發(fā)現(xiàn),服務存在cpu持續(xù)100%的情況,下面分享一下我的處理方案和過程,需要的朋友可以參考下
    2024-05-05
  • Spring Security組件一鍵接入驗證碼登錄和小程序登錄的詳細過程

    Spring Security組件一鍵接入驗證碼登錄和小程序登錄的詳細過程

    這篇文章主要介紹了Spring Security 一鍵接入驗證碼登錄和小程序登錄,簡單介紹一下這個插件包的相關知識,本文結合示例代碼給大家介紹的非常詳細,需要的朋友參考下吧
    2022-04-04
  • Springboot整合hutool驗證碼的實例代碼

    Springboot整合hutool驗證碼的實例代碼

    在 Spring Boot 中,你可以將 Hutool 生成驗證碼的功能集成到 RESTful API 接口中,這篇文章主要介紹了Springboot整合hutool驗證碼,需要的朋友可以參考下
    2024-08-08
  • 詳解Java9新特性中的模塊化與反射機制

    詳解Java9新特性中的模塊化與反射機制

    Java9中的一個重大變化就是引入了模塊化系統(tǒng),這個系統(tǒng)使得Java應用程序的構建、發(fā)布和部署更加具有可控性和可重用性,與此同時,Java9還改進了反射機制,讓它與模塊化系統(tǒng)更好地配合,本文通過代碼示例介紹的非常詳細,需要的朋友可以參考下
    2023-06-06
  • java設計模式策略模式圖文示例詳解

    java設計模式策略模式圖文示例詳解

    這篇文章主要為大家介紹了java設計模式策略模式圖文示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2022-06-06
  • Springboot如何設置靜態(tài)資源緩存一年

    Springboot如何設置靜態(tài)資源緩存一年

    這篇文章主要介紹了Springboot如何設置靜態(tài)資源緩存一年,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2019-11-11
  • Java去掉數字字符串開頭的0三種方法(推薦)

    Java去掉數字字符串開頭的0三種方法(推薦)

    下面小編就為大家?guī)硪黄狫ava去掉數字字符串開頭的0三種方法(推薦)。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-05-05

最新評論