亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Java spring事務(wù)及事務(wù)不生效的原因詳解

 更新時(shí)間:2021年09月09日 10:52:52   作者:一念既出,萬(wàn)山無(wú)阻  
在日常編碼過(guò)程中常常涉及到事務(wù),在前兩天看到一篇文章提到了Spring事務(wù),那么在此總結(jié)下在Spring環(huán)境下事務(wù)失效的幾種原因

注解 @Transactional 的屬性參數(shù)

屬性 類型 描述
value String 可選,指定事務(wù)管理器
propagation enum: Propagation 可選,指定事務(wù)傳播行為
isolation enum: Isolation 可選,指定事務(wù)隔離級(jí)別
readOnly boolean 讀寫或只讀事務(wù),默認(rèn)讀寫
timeout int (in seconds granularity) 事務(wù)超時(shí)時(shí)間設(shè)置
rollbackFor Class 對(duì)象數(shù)組,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類數(shù)組
rollbackForClassName 類名數(shù)組,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
noRollbackFor Class對(duì)象數(shù)組,必須繼承自Throwable 不會(huì)導(dǎo)致事務(wù)回滾的異常類數(shù)組
noRollbackForClassName 類名數(shù)組,必須繼承自Throwable 不會(huì)導(dǎo)致事務(wù)回滾的

propagation 事務(wù)的傳播機(jī)制

事務(wù)的傳播機(jī)制:如果在開(kāi)始當(dāng)前事務(wù)之前,一個(gè)事務(wù)上下文已經(jīng)存在,此時(shí)有若干選項(xiàng)可以指定一個(gè)事務(wù)性方法的執(zhí)行行為

枚舉 Propagation 中定義了 7 個(gè)傳播機(jī)制的值

  • Propagation.REQUIRED:如果當(dāng)前沒(méi)有事務(wù),就新建一個(gè)事務(wù),如果已經(jīng)存在一個(gè)事務(wù)中,加入到這個(gè)事務(wù)中。是 spring 默認(rèn)的傳播機(jī)制
  • Propagation.SUPPORTS:持當(dāng)前事務(wù),如果當(dāng)前有事務(wù),就以事務(wù)方式執(zhí)行;如果當(dāng)前沒(méi)有事務(wù),就以非事務(wù)方式執(zhí)行
  • Propagation.MANDATORY:使用當(dāng)前的事務(wù),且必須在一個(gè)已有的事務(wù)中執(zhí)行,如果當(dāng)前不存在事務(wù),否則拋出異常
  • Propagation.REQUIRES_NEW:不管是否存在事務(wù),都創(chuàng)建一個(gè)新的事務(wù),原來(lái)的掛起,新的執(zhí)行完畢,繼續(xù)執(zhí)行老的事務(wù)
  • Propagation.NOT_SUPPORTED:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起
  • Propagation.NEVER:以非事務(wù)方式執(zhí)行,且必須在一個(gè)沒(méi)有的事務(wù)中執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常
  • Propagation.NESTED:如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行;如果當(dāng)前沒(méi)有事務(wù),則執(zhí)行與 Propagation.REQUIRED 類似的操作

isolation 事務(wù)的隔離級(jí)別

隔離級(jí)別:若干個(gè)并發(fā)的事務(wù)之間的隔離程度,與我們開(kāi)發(fā)時(shí)候主要相關(guān)的場(chǎng)景包括:臟讀取、重復(fù)讀、幻讀

枚舉 Isolation 中定義了 5 個(gè)表示隔離級(jí)別的值

  • Isolation.DEFAULT:使用各個(gè)數(shù)據(jù)庫(kù)默認(rèn)的隔離級(jí)別,是 spring 默認(rèn)的隔離級(jí)別
  • Isolation.READ_UNCOMMITTED:讀取未提交數(shù)據(jù)(會(huì)出現(xiàn)臟讀, 不可重復(fù)讀)
  • Isolation.READ_COMMITTED:讀取已提交數(shù)據(jù)(會(huì)出現(xiàn)不可重復(fù)讀和幻讀)
  • Isolation.REPEATABLE_READ:可重復(fù)讀(會(huì)出現(xiàn)幻讀)
  • Isolation.SERIALIZABLE:串行化

常用數(shù)據(jù)庫(kù)的默認(rèn)隔離級(jí)別

MYSQL:默認(rèn)為 REPEATABLE_READ

SQLSERVER:默認(rèn)為 READ_COMMITTED

Oracle:默認(rèn)為 READ_COMMITTED

readOnly 事務(wù)的讀寫性

默認(rèn)情況下是 false(不指定只讀性);設(shè)置為 true 的含義: 該方法下使用的是只讀操作,如果進(jìn)行其他非讀操作,則會(huì)跑出異常

事務(wù)的只讀性概念

從這一點(diǎn)設(shè)置的時(shí)間點(diǎn)開(kāi)始(時(shí)間點(diǎn) a),到這個(gè)事務(wù)結(jié)束的過(guò)程中,其他事務(wù)所提交的數(shù)據(jù),該事務(wù)將看不見(jiàn)??!即查詢中不會(huì)出現(xiàn)別人在時(shí)間點(diǎn) a 之后提交的數(shù)據(jù)

應(yīng)用場(chǎng)景

  • 如果你一次執(zhí)行單條查詢語(yǔ)句,則沒(méi)有必要啟用事務(wù)的只讀性支持,數(shù)據(jù)庫(kù)默認(rèn)支持 SQL 執(zhí)行期間的讀一致性
  • 如果你一次執(zhí)行多條查詢語(yǔ)句,例如統(tǒng)計(jì)查詢,報(bào)表查詢。在這種場(chǎng)景下,多條查詢 SQL 必須保證整體的讀一致性;否則,在前條 SQL 查詢之后,后條 SQL 查詢之前,數(shù)據(jù)被其他用戶改變,則該次整體的統(tǒng)計(jì)查詢將會(huì)出現(xiàn)讀數(shù)據(jù)不一致的狀態(tài)。此時(shí),就有必要啟用事務(wù)的只讀性支持

是一次執(zhí)行多次查詢來(lái)統(tǒng)計(jì)某些信息,這時(shí)為了保證數(shù)據(jù)整體的一致性,要用只讀事務(wù)

timeout 超時(shí)時(shí)間

  • 用于設(shè)置事務(wù)處理的時(shí)間長(zhǎng)度,阻止可能出現(xiàn)的長(zhǎng)時(shí)間的阻塞系統(tǒng)或者占用系統(tǒng)資源,單位為秒
  • 如果超時(shí)設(shè)置事務(wù)回滾,并拋出 TransactionTimedOutException 異常

rollbackFor 和 rollbackForClassName 遇到時(shí)回滾

  • 用來(lái)指明回滾的條件是哪些異常類或者異常類名
  • spring 默認(rèn)情況下會(huì)對(duì)運(yùn)行期異常 RunTimeException 進(jìn)行事務(wù)回滾,如果遇到 checked 異常就不回滾

noRollbackFor 和 noRollbackForClassName 遇到時(shí)不回滾

用來(lái)指明不回滾的條件是哪些異常類或者異常類名

value 指定使用的事務(wù)管理器

  • value 主要用來(lái)指定不同的事務(wù)管理器,主要用來(lái)滿足在同一個(gè)系統(tǒng)中,存在不同的事務(wù)管理器的場(chǎng)景需要
  • 比如,在 spring 中聲明了兩種事務(wù)管理器 txManager1,txManager2。然后用戶可以根據(jù)需要,修改這個(gè)參數(shù)來(lái)指定特定的 txManage

存在多個(gè)事務(wù)管理器的情況:在一個(gè)系統(tǒng)中,需要訪問(wèn)多個(gè)數(shù)據(jù)源,則必然會(huì)配置多個(gè)事務(wù)管理器

spring 事務(wù)不生效的原因

spring 團(tuán)隊(duì)建議在具體的 類或類的方法上 使用 @Transactional 注解,而不要使用在類所要實(shí)現(xiàn)的任何接口上。在接口上使用 @Transactional 注解,只能當(dāng)你設(shè)置了基于接口的代理時(shí)它才生效。因?yàn)樽⒔馐遣荒芾^承的,這就意味著如果正在使用基于類的代理時(shí),那么事務(wù)的設(shè)置將不能被基于類的代理所識(shí)別,而且對(duì)象也將不會(huì)被事務(wù)代理所包裝

對(duì) spring 來(lái)說(shuō),方法調(diào)用者所屬的類或方法調(diào)用者就是主體對(duì)象,spring 會(huì)從二者身上獲取合適的事務(wù)增強(qiáng)器和事務(wù)屬性,如果獲取不到合適的增強(qiáng)器和事務(wù)屬性,那么事務(wù)就會(huì)失效

數(shù)據(jù)庫(kù)引擎不支持事務(wù)

比如我們常用的 mysql,從 mysql 5.5.5 開(kāi)始的默認(rèn)存儲(chǔ)引擎是 InnoDB,之前默認(rèn)的都是 MyISAM,引擎 MyISAM 是不支持事務(wù)操作的,需要改成 InnoDB 才能支持。所以這點(diǎn)要值得注意,底層引擎不支持事務(wù)再怎么搞都是白搭

@Transactional 所在類非 spring 容器的 bean

// @Service 
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void updateOrder(Order order) {
        // update order
    }
}

如果此時(shí)把 @Service 注解注釋掉,這個(gè)類就不會(huì)被加載成一個(gè) bean,那這個(gè)類就不會(huì)被 spring 管理了,事務(wù)自然就失效了

方法不是 public 的

spring 事務(wù)官方文檔

Method visibility and @Transactional
When you use proxies, you should apply the @Transactional annotation only to methods with
public visibility. If you do annotate protected, private or package-visible methods with the
@Transactional annotation, no error is raised, but the annotated method does not exhibit the
configured transactional settings. If you need to annotate non-public methods, consider using
AspectJ (described later).

@Transactional 只能用于 public 的方法上,否則事務(wù)會(huì)失效;即使方法是 public 的,但是如果被 private 的方法調(diào)用,事務(wù)同樣也會(huì)失效

數(shù)據(jù)源沒(méi)有配置事務(wù)管理器

@Bean
public PlatformTransactionManager transactionManager(DataSource dataSource) {
    return new DataSourceTransactionManager(dataSource);
}

當(dāng)前數(shù)據(jù)源如果沒(méi)有配置事務(wù)管理器,那事務(wù)是不會(huì)生效的

事務(wù)的 propagation 傳播機(jī)制設(shè)置錯(cuò)誤

@Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void update(Order order) {
        updateOrder(order);
    }
    @Transactional(propagation = Propagation.NOT_SUPPORTED)
    public void updateOrder(Order order) {
        // update order
    }
}

Propagation.NOT_SUPPORTED:以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起

catch 語(yǔ)句沒(méi)有拋出異常

@Service
public class ClassServiceImpl implements ClassService {
    @Override
    @Transactional
    public void insertClassByException(ClassDo classDo) {
        classMapper.insertClass(classDo);
        try {
            int i = 1 / 0;
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

把異常吃了,然后又不拋出來(lái),事務(wù)也不會(huì)回滾!

拋出的異常類型錯(cuò)誤

@Service
public class OrderServiceImpl implements OrderService {
    @Transactional
    public void updateOrder(Order order) {
        try {
            // update order
        } catch {
            throw new Exception("更新錯(cuò)誤");
        }
    }
}

@Transactional 默認(rèn)回滾的是 RuntimeException Error,而 Exception RuntimeException 的父類,事務(wù)不生效的

如果你想觸發(fā)其他異常的回滾,需要在注解上配置一下,如

@Transactional(rollbackFor = Exception.class)

確保業(yè)務(wù)和事務(wù)入口在同一個(gè)線程

@Transactional
@Override
public void save(User user1, User user2) {
    new Thread(() -> {
          saveError(user1, user2);
          System.out.println(1 / 0);
    }).start();
}

自身調(diào)用問(wèn)題

案列一

@Transactional 的事務(wù)開(kāi)啟,或者是基于接口的或者是基于類的代理被創(chuàng)建。所以在同一個(gè)類中一個(gè)無(wú)事務(wù)的方法調(diào)用另一個(gè)有事務(wù)的方法,事務(wù)是不會(huì)起作用的 (這就是業(yè)界老問(wèn)題:類內(nèi)部方法調(diào)用事務(wù)不生效的問(wèn)題原因)

在這里插入圖片描述

因?yàn)?code> addInfo()上沒(méi)有事務(wù),而 addInfo() 調(diào)用 create() 的時(shí)候是類內(nèi)部調(diào)用,沒(méi)有走代理類,也就沒(méi)有事務(wù)切面

案列二

事務(wù)生效

在這里插入圖片描述

由于 spring 事務(wù)默認(rèn)的傳播機(jī)制是 Propagation.REQUIRED,create() 方法的事務(wù)會(huì)加入到 addInfo() 方法的事務(wù)之中;而所在的類是可以產(chǎn)生代理對(duì)象的

案列三

事務(wù)生效

在這里插入圖片描述

由于 spring 事務(wù)默認(rèn)的傳播機(jī)制是 Propagation.REQUIRED,create() 方法的事務(wù)會(huì)加入到 addInfo() 方法的事務(wù)之中;而所在的類是可以產(chǎn)生代理對(duì)象的

案列四

事務(wù)生效

在這里插入圖片描述

案列五

事務(wù)生效

在這里插入圖片描述

這里雖然是方法內(nèi)部調(diào)用,但是事務(wù)切入了 addInfo() 方法,所以即使內(nèi)部拋出異常,也是可以生效的

案列六

事務(wù)不生效

在這里插入圖片描述

案列七

事務(wù)生效

在這里插入圖片描述

這是我們解決方法內(nèi)部調(diào)用事務(wù)不生效的最常用方法之一:內(nèi)部維護(hù)一個(gè)注入自己的 bean,然后使用這個(gè)屬性來(lái)調(diào)用方法。其實(shí)還有一種方法,那就是利用 Aop 上下文來(lái)獲取代理對(duì)象((TestService)AopContext.currentProxy()).create();,然后通過(guò)代理對(duì)象來(lái)調(diào)用。這里需要注意:Aop 上下文 spring 默認(rèn)是關(guān)閉的,需要手動(dòng)開(kāi)啟

總結(jié)

本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • SpringBoot中使用攔截器的配置詳解

    SpringBoot中使用攔截器的配置詳解

    這篇文章主要介紹了SpringBoot中使用攔截器的配置詳解,攔截器是?AOP?的一種實(shí)現(xiàn),專門攔截對(duì)動(dòng)態(tài)資源的后臺(tái)請(qǐng)求,即攔截對(duì)控制層的請(qǐng)?求,使用場(chǎng)景比較多的是判斷用戶是否有權(quán)限請(qǐng)求后臺(tái),需要的朋友可以參考下
    2024-01-01
  • 帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之二叉樹(shù)

    帶你了解Java數(shù)據(jù)結(jié)構(gòu)和算法之二叉樹(shù)

    這篇文章主要為大家介紹了Java數(shù)據(jù)結(jié)構(gòu)和算法之二叉樹(shù),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來(lái)幫助
    2022-01-01
  • SpringBoot攔截器Filter的使用方法詳解

    SpringBoot攔截器Filter的使用方法詳解

    這篇文章主要介紹了SpringBoot攔截器Filter的使用方法詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-03-03
  • java使用ftp上傳文件示例分享

    java使用ftp上傳文件示例分享

    這篇文章主要介紹了java使用ftp上傳文件示例,需要的朋友可以參考下
    2014-02-02
  • Java JDK11的下載與安裝教程

    Java JDK11的下載與安裝教程

    這篇文章主要介紹了Java JDK11的下載與安裝,本文以win10為例給大家講解win10系統(tǒng)下載安裝jdk11的教程,需要的朋友可以參考下
    2023-05-05
  • springboot如何關(guān)掉tomcat容器

    springboot如何關(guān)掉tomcat容器

    這篇文章主要介紹了springboot如何關(guān)掉tomcat容器,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2021-11-11
  • IDEA與模擬器安裝調(diào)試失敗的處理方法:INSTALL_PARSE_FAILED_NO_CERTIFICATES

    IDEA與模擬器安裝調(diào)試失敗的處理方法:INSTALL_PARSE_FAILED_NO_CERTIFICATES

    這篇文章主要介紹了IDEA與模擬器安裝調(diào)試失敗的處理方法:INSTALL_PARSE_FAILED_NO_CERTIFICATES,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-09-09
  • SpringBoot實(shí)現(xiàn)線程池

    SpringBoot實(shí)現(xiàn)線程池

    現(xiàn)在由于系統(tǒng)越來(lái)越復(fù)雜,導(dǎo)致很多接口速度變慢,這時(shí)候就會(huì)想到可以利用線程池來(lái)處理一些耗時(shí)并不影響系統(tǒng)的操作。本文就介紹了SpringBoot線程池的使用,感興趣的可以了解一下
    2021-06-06
  • 基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控步驟

    基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控步驟

    這篇文章主要介紹了基于Idea+Jconsole實(shí)現(xiàn)線程監(jiān)控功能,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-04-04
  • spring.mvc.servlet.load-on-startup屬性方法源碼解讀

    spring.mvc.servlet.load-on-startup屬性方法源碼解讀

    這篇文章主要介紹了spring.mvc.servlet.load-on-startup的屬性方法源碼解讀,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-12-12

最新評(píng)論