最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

關于@Transactional事務嵌套使用方式

 更新時間:2024年11月08日 14:25:15   作者:夏詩曼CharmaineXia  
Spring框架通過@Transactional注解來管理事務,它可以作用于類和方法上,用于聲明事務的屬性,如傳播行為、隔離級別、超時時間等,Spring事務是基于AOP實現的,它在運行時為加了@Transactional注解的方法或類創(chuàng)建代理

一、概述

事務(Transaction):指數據庫中執(zhí)行的一系列操作被視為一個邏輯單元,要么全部成功地執(zhí)行,要么全部失敗回滾,保證數據的一致性和完整性。

@Transactional注解是Spring框架提供的用于聲明事務的注解,作用于類和方法上。

1.1 @Transactional注解

屬性可選值作用
propagationREQUIREDREQUIRES_NEWNESTEDNOT_SUPPORTEDSUPPORTSMANDATORY指定事務的傳播行為,在事務嵌套時起作用,默認值為Propagation.REQUIRED
isolationDEFAULT(和數據表一致)READ_UNCOMMITTED(讀-未提交)READ_COMMITTED(讀已提交)REPEATABLE_READ(可重復讀)SERIALIZABLE(串行化)指定事務的隔離級別,和數據庫的事務一致,默認值為Isolation.DEFAULT
readOnlytruefalse指定事務是否為只讀事務,默認值為false。如果將其設置為true,表示事務只涉及讀取操作
timeout數字(秒)指定事務的超時時間(秒),默認值為TransactionDefinition.TIMEOUT_DEFAULT。如果事務在指定的時間內未完成,將被自動回滾
rollbackFor異常類.Class指定觸發(fā)事務回滾的異常類型數組,默認為空。當方法拋出指定類型的異常時,事務將回滾
noRollbackFor異常類.Class指定不觸發(fā)事務回滾的異常類型數組,默認為空。當方法拋出指定類型的異常時,事務將不回滾
rollbackForClassName異常類名與rollbackFor類似,但是使用異常類型的完全限定名字符串來指定觸發(fā)事務回滾的異常
noRollbackForClassName異常類名與noRollbackFor類似,但是使用異常類型的完全限定名字符串來指定不觸發(fā)事務回滾的異常

1.2 Spring事務原理

Spring的事務是依靠aop實現的。

是在程序運行時給代理對象創(chuàng)建代理類。

如果方法或類上添加了@Transcation注解,spring會自動給方法或類創(chuàng)建一個代理類,代理類中包含了開關事務的代碼和原始操作。

示意圖如下(原始類指加了@Transcation的類):

  

如果嵌套調用呢?  

method1方法上有事務注解,method2沒有,method1調用了method2。

會生成如下的代理類:

二、@Transactional使用

2.1 事務失效的7種情況

這里用一個demo舉例子:更新一條數據,我們先刪除數據,再插入新數據(主鍵自動遞增)。

我們希望刪除或插入哪一方失敗,數據庫都能回滾。Spring事務失效是指發(fā)生異常依然不回滾。

1. 同一個類中方法調用

開發(fā)中避免不了會對同?個類??的?法調?,?如有?個類 Test,它的?個?法 A,A 再調?本類的?法 B(不論?法 B 是? public 還是 private 修飾),但?法 A 沒有聲明注解事務,? B ?法有。

外部調??法 A 之后,?法 B 的事務是不會起作?的,這也是經常犯錯誤的?個地?。

public class Test{
    //外層
    public void A(Category category) {
        this.categoryDao.delete(category);
        this.B(category);//無事務,但有異常
    }
    
    //內層
    @Transactional
    public void B(Category category) {
    	this.categoryDao.insert(category);
        int a=2/0;
    }
}

為什么失效:

其實這還是由于使? Spring AOP 代理造成的,沒加@Transactional注解的方法不會被代理類重寫,也就不會有事務。

2. 異常被 catch 住,而且沒有再次拋出異常

無論是外層異常還是內層異常,只要捕獲以后沒有拋出異常,都不會回滾??偟膩碚f沒有異常不會回滾。

	//外層
    @Transactional
    public void updateById(Category category) {
        try {
            this.categoryDao.deleteById(category.getCid());
            this.categoryDao.insert(category);
            int a=2/0;
        }catch (java.lang.Exception e){
            System.out.println("updateById異常");
        }
    }
    //外層
    public void update(Category category) {
        this.delete(category);
        this.categoryDao.insert(category);
    }
	
	//內層
	@Transactional
    void delete(Category category) {
    	try{
	        this.categoryDao.delete(category.getId);
	        int a=2/0;
        }catch(Exception e){

		}
    }

解決辦法:

捕獲后再次拋出異常。無論是內層、外層,只要重新拋出異常,就可以回滾。

    //外層
    public void update(Category category) {
        this.delete(category);
        this.categoryDao.insert(category);
    }
	
	//內層
	@Transactional
    void delete(Category category) {
    	try{
	        this.categoryDao.delete(category.getId);
	        int a=2/0;
        }catch(Exception e){
			throw new RuntimeException("service層deleteById方法異常");//可以自定義異常
		}
    }

結論:沒有異常不會回滾。

3. 拋出RuntimeException或Error以外的異常

@Transcation有個屬性(方法),管理何種異常會引發(fā)回滾。  

默認情況下,事務只在RuntimeException和Error上回滾。

拋出RuntimeException和Error以外類型的異常,不會回滾。 

常見的非運行時異常有:SQLException、IOException、FileNotFoundException、ReflectiveOperationException等等。

	@Transactional
    void delete(Category category) throws SQLException{
        this.categoryDao.delete(category.getId);
        int a=2/0;
       	throw new SQLException("xxx");  //拋出異常也不會回滾
    }

解決辦法:

使用RollbackFor屬 添加 要捕獲的異常類型,這樣除了RuntimeException和Error類型的異常,遇到Exception以及它的子類的異常,也會發(fā)生回滾。

	@Transactional(rollbackFor = Exception.class)
    void delete(Category category) throws SQLException{
        this.categoryDao.delete(category.getId);
        int a=2/0;
       	throw new SQLException("xxx");  //這下就回滾了
    }

結論:使用RollbackFor屬性添加要捕獲的異常類型

4. 子線程內異常

刪除操作新開一個線程執(zhí)行,并且執(zhí)行中發(fā)生異常。結果是刪除回滾,插入沒回滾。

多線程環(huán)境下,內外層是兩個事務,事務具有隔離性,事務之間不會互相干擾。

    //外層
    @Transactional(rollbackFor = java.lang.Exception.class)
    public void update(Category category) {
        Thread thread=new Thread(new Runnable() {
           @Override
           public void run() {
                delete(category);//刪除
            }
        });
        this.categoryDao.insert(category);//插入
    }
	
	//內層
	@Transactional(rollbackFor = java.lang.Exception.class)
    void delete(Category category) {
        this.categoryDao.delete(category.getId);
        int a=2/0; //異常
    }

解決辦法:

使用Thread.UncaughtExceptionHandler接口捕獲線程異常,主線程發(fā)現了異常,也跟著回滾。

注:事務還是多個事務

1.創(chuàng)建一個實現了Thread.UncaughtExceptionHandler接口的異常處理器類,該類將負責捕獲未被捕獲的(沒加try-catch的)線程異常并進行處理:

public class CustomUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        // 在此可以處理未被捕獲的線程異常
        System.out.println("線程 " + t.getName() + " 發(fā)生了異常: " + e.getMessage());
    }
}

2.在主線程或創(chuàng)建的子線程中,設置自定義的異常處理器:

    @Transactional(rollbackFor = java.lang.Exception.class)
    public void updateById(Category category){
        Thread.setDefaultUncaughtExceptionHandler(new CustomUncaughtExceptionHandler());//加上這句
        Thread thread=new Thread(new Runnable() {
            @Override
            public void run() {
                deleteById(category.getCid());//刪除
            }
        });
        thread.start();
        this.categoryDao.insert(category);//插入
    }

結論:子線程異常拋給主線程,兩者一起回滾。

5. 事務方法是private、static、final的

事務是依賴AOP實現的,如果方法不能被重寫,就不能生產代理類。

結論:java實現的動態(tài)代理的原理是代理類實現被代理類的相同接口、或成為被代理類的子類,然后重寫相同方法

6. 數據庫不支持事務

mysql的MyISAM存儲引擎是不支持事務的,它是舊版 MySQL(MySQL 5.5 之前)中的默認存儲引擎。 

7. 設置了某些事務傳播行為

在事務嵌套的時候,設置了以下傳播行為,會讓事務掛起(相當于沒有事務)或拋異常。

  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當前存在事務,則加?該事務;如果當前沒有事務,則以?事務的?式繼續(xù)運?。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以?事務?式運?,如果當前存在事務,則把當前事務掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以?事務?式運?,如果當前存在事務,則拋出異常
    //外層
    @Transactional
    public void A(Category category) {
        this.categoryDao.insert(category);
        this.B(category.getCid());
    }
	
	//內層
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public boolean B(Integer cid) {
        int i = this.categoryDao.deleteById(cid);
        if(i>0) {
            throw new RuntimeException("xxx"); 
        }
        return true;
    }

2.2 事務6種傳播機制

默認是REQUIERD,保證只有一個事務。

總結

spring相當多的功能都用到了動態(tài)代理,還需要對這方面知識做個總結,學無止境啊。

相關文章

  • JAVA裝飾者模式(從現實生活角度理解代碼原理)

    JAVA裝飾者模式(從現實生活角度理解代碼原理)

    裝飾者模式可以動態(tài)地給一個對象添加一些額外的職責。就增加功能來說,Decorator模式相比生成子類更為靈活。這篇文章主要介紹了JAVA裝飾者模式的相關資料,需要的朋友可以參考下
    2016-12-12
  • Java面向對象之什么是異常

    Java面向對象之什么是異常

    Java 把異常當作對象來處理,并定義一個基類,java.lang.Throwable 作為所有異常的超類。今天通過本文給大家分享Java面向對象之什么是異常,感興趣的朋友一起看看吧
    2021-07-07
  • Spring MVC溫故而知新系列教程之從零開始

    Spring MVC溫故而知新系列教程之從零開始

    Spring MVC 框架在 Java 的 Web 項目中應該是無人不知的吧,你不會搭建一個 Spring 框架?作為身為一個剛剛學習Java的我都會,如果你不會的話,那可真令人憂傷。下面這篇文章主要給大家介紹了關于Spring MVC從零開始的相關資料,需要的朋友可以參考下
    2018-05-05
  • springboot中請求地址轉發(fā)的兩種方案

    springboot中請求地址轉發(fā)的兩種方案

    在開發(fā)過程中,我們經常需要將請求從一個服務轉發(fā)到另一個服務,以實現不同服務之間的協(xié)作,本文主要介紹了springboot中請求地址轉發(fā)的兩種方案,感興趣的可以了解一下
    2023-11-11
  • spring boot實現驗證碼功能

    spring boot實現驗證碼功能

    這篇文章主要為大家詳細介紹了spring boot實現驗證碼功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-07-07
  • Java如何處理數據成為樹狀結構

    Java如何處理數據成為樹狀結構

    這篇文章主要介紹了Java如何處理數據成為樹狀結構問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-07-07
  • Java NIO Buffer過程詳解

    Java NIO Buffer過程詳解

    這篇文章主要介紹了Java NIO Buffer過程詳解,緩沖區(qū)在java nio中負責數據的存儲。緩沖區(qū)就是數組。用于存儲不同數據類型的數據。,需要的朋友可以參考下
    2019-06-06
  • 詳解使用Spring Boot開發(fā)Web項目

    詳解使用Spring Boot開發(fā)Web項目

    這篇文章主要介紹了詳解使用Spring Boot開發(fā)Web項目,具有一定的參考價值,感興趣的小伙伴們可以參考一下。
    2017-04-04
  • 如何將java或javaweb項目打包為jar包或war包

    如何將java或javaweb項目打包為jar包或war包

    本文主要介紹了如何將java或javaweb項目打包為jar包或war包,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2022-07-07
  • MyBatis Map結果的Key轉為駝峰式

    MyBatis Map結果的Key轉為駝峰式

    今天小編就為大家分享一篇關于MyBatis Map結果的Key轉為駝峰式,小編覺得內容挺不錯的,現在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧
    2018-12-12

最新評論

海晏县| 忻城县| 常宁市| 萨迦县| 雷山县| 潼南县| 甘谷县| 通海县| 耒阳市| 盐城市| 晋州市| 改则县| 五峰| 普宁市| 鄢陵县| 定安县| 临朐县| 太原市| 桃源县| 兴和县| 驻马店市| 仪征市| 广南县| 太原市| 公安县| 通海县| 津南区| 浏阳市| 马公市| 汤原县| 上饶县| 象州县| 澄江县| 古浪县| 昭苏县| 浑源县| 伊春市| 南平市| 驻马店市| 安岳县| 桂林市|