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

關(guān)于@Transactional事務(wù)嵌套使用方式

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

一、概述

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

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

1.1 @Transactional注解

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

1.2 Spring事務(wù)原理

Spring的事務(wù)是依靠aop實(shí)現(xiàn)的。

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

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

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

  

如果嵌套調(diào)用呢?  

method1方法上有事務(wù)注解,method2沒有,method1調(diào)用了method2。

會生成如下的代理類:

二、@Transactional使用

2.1 事務(wù)失效的7種情況

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

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

1. 同一個類中方法調(diào)用

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

外部調(diào)??法 A 之后,?法 B 的事務(wù)是不會起作?的,這也是經(jīng)常犯錯誤的?個地?。

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

為什么失效:

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

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

無論是外層異常還是內(nèi)層異常,只要捕獲以后沒有拋出異常,都不會回滾??偟膩碚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);
    }
	
	//內(nèi)層
	@Transactional
    void delete(Category category) {
    	try{
	        this.categoryDao.delete(category.getId);
	        int a=2/0;
        }catch(Exception e){

		}
    }

解決辦法:

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

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

結(jié)論:沒有異常不會回滾。

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

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

默認(rèn)情況下,事務(wù)只在RuntimeException和Error上回滾。

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

常見的非運(yùn)行時異常有: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");  //這下就回滾了
    }

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

4. 子線程內(nèi)異常

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

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

    //外層
    @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);//插入
    }
	
	//內(nèi)層
	@Transactional(rollbackFor = java.lang.Exception.class)
    void delete(Category category) {
        this.categoryDao.delete(category.getId);
        int a=2/0; //異常
    }

解決辦法:

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

注:事務(wù)還是多個事務(wù)

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

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)建的子線程中,設(shè)置自定義的異常處理器:

    @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);//插入
    }

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

5. 事務(wù)方法是private、static、final的

事務(wù)是依賴AOP實(shí)現(xiàn)的,如果方法不能被重寫,就不能生產(chǎn)代理類。

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

6. 數(shù)據(jù)庫不支持事務(wù)

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

7. 設(shè)置了某些事務(wù)傳播行為

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

  • TransactionDefinition.PROPAGATION_SUPPORTS:如果當(dāng)前存在事務(wù),則加?該事務(wù);如果當(dāng)前沒有事務(wù),則以?事務(wù)的?式繼續(xù)運(yùn)?。
  • TransactionDefinition.PROPAGATION_NOT_SUPPORTED:以?事務(wù)?式運(yùn)?,如果當(dāng)前存在事務(wù),則把當(dāng)前事務(wù)掛起。
  • TransactionDefinition.PROPAGATION_NEVER:以?事務(wù)?式運(yùn)?,如果當(dāng)前存在事務(wù),則拋出異常
    //外層
    @Transactional
    public void A(Category category) {
        this.categoryDao.insert(category);
        this.B(category.getCid());
    }
	
	//內(nèi)層
    @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 事務(wù)6種傳播機(jī)制

默認(rèn)是REQUIERD,保證只有一個事務(wù)。

總結(jié)

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

相關(guān)文章

  • Java中工具Jstack的使用實(shí)例

    Java中工具Jstack的使用實(shí)例

    jstack用于生成java虛擬機(jī)當(dāng)前時刻的線程快照,下面這篇文章主要給大家介紹了關(guān)于Java中工具Jstack使用的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2022-04-04
  • MultipartFile文件判斷是否存在的操作

    MultipartFile文件判斷是否存在的操作

    這篇文章主要介紹了MultipartFile文件判斷是否存在的操作,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-07-07
  • 解決eclipse上傳svn忽略target文件夾的坑

    解決eclipse上傳svn忽略target文件夾的坑

    這篇文章主要介紹了解決eclipse上傳svn忽略target文件夾的坑,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2021-01-01
  • 詳解DES加密算法的原理與Java實(shí)現(xiàn)

    詳解DES加密算法的原理與Java實(shí)現(xiàn)

    DES 加密,是對稱加密。對稱加密,顧名思義,加密和解密的運(yùn)算全都是使用的同樣的秘鑰。這篇文章主要為大家講講DES加密算法的原理與Java實(shí)現(xiàn),需要的可以參考一下
    2022-10-10
  • JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法總結(jié)(省時間省空間)

    JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法總結(jié)(省時間省空間)

    隨機(jī)數(shù)在實(shí)際中使用很廣泛,比如要隨即生成一個固定長度的字符串、數(shù)字,這篇文章主要給大家介紹了關(guān)于JAVA生成八位不重復(fù)隨機(jī)數(shù)最快的方法,文中介紹的方法省時間省空間,需要的朋友可以參考下
    2024-03-03
  • MyBatis實(shí)現(xiàn)數(shù)據(jù)庫類型和Java類型的轉(zhuǎn)換

    MyBatis實(shí)現(xiàn)數(shù)據(jù)庫類型和Java類型的轉(zhuǎn)換

    MyBatis 在處理數(shù)據(jù)庫查詢結(jié)果或傳遞參數(shù)時,需要將數(shù)據(jù)庫類型與 Java 類型之間進(jìn)行轉(zhuǎn)換,本文就給大家介紹MyBatis如何實(shí)現(xiàn)數(shù)據(jù)庫類型和 Java 類型的轉(zhuǎn)換的,需要的朋友可以參考下
    2024-09-09
  • 使用Spring Boot Maven插件的詳細(xì)方法

    使用Spring Boot Maven插件的詳細(xì)方法

    這篇文章主要介紹了如何使用Spring Boot Maven插件,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2023-05-05
  • 基于Arrays.sort()和lambda表達(dá)式

    基于Arrays.sort()和lambda表達(dá)式

    這篇文章主要介紹了Arrays.sort()和lambda表達(dá)式,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-12-12
  • SpringBoot中的跨域詳解

    SpringBoot中的跨域詳解

    這篇文章主要介紹了SpringBoot中的跨域詳解,在瀏覽器上當(dāng)前訪問的網(wǎng)站,向另一個網(wǎng)站發(fā)送請求,用于獲取數(shù)據(jù)的過程就是跨域請求,跨域是瀏覽器的同源策略決定的,是一個重要的瀏覽器安全策略,需要的朋友可以參考下
    2023-08-08
  • Java 數(shù)組的兩種初始化方式

    Java 數(shù)組的兩種初始化方式

    這篇文章主要介紹了Java 數(shù)組的兩種初始化方式,幫助大家更好的理解和學(xué)習(xí)使用Java,感興趣的朋友可以了解下
    2021-02-02

最新評論