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

一文搞懂spring boot本地事務(wù)@Transactional參數(shù)

 更新時(shí)間:2021年10月09日 10:51:24   作者:cyb-xh  
這篇文章主要介紹了spring boot本地事務(wù)@Transactional參數(shù)詳解,本文通過(guò)示例代碼圖文相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下

1. 本地事務(wù)

商品新增功能非常復(fù)雜,商品管理微服務(wù)在service層中調(diào)用保存spu和sku相關(guān)的方法,為了保證數(shù)據(jù)的一致性,必然會(huì)使用事務(wù)。

在JavaEE企業(yè)級(jí)開(kāi)發(fā)的應(yīng)用領(lǐng)域,為了保證數(shù)據(jù)的完整性和一致性,必須引入數(shù)據(jù)庫(kù)事務(wù)的概念,所以事務(wù)管理是企業(yè)級(jí)應(yīng)用程序開(kāi)發(fā)中必不可少的技術(shù)。

咱們之前玩的事務(wù)都是本地事務(wù)。所謂本地事務(wù),是指該事務(wù)僅在當(dāng)前項(xiàng)目?jī)?nèi)有效。

1.1. 基本概念

事務(wù)的概念:事務(wù)是邏輯上一組操作,組成這組操作各個(gè)邏輯單元,要么一起成功,要么一起失敗。

事務(wù)的四個(gè)特性(ACID):

  1. 原子性(atomicity):“原子”的本意是“不可再分”,事務(wù)的原子性表現(xiàn)為一個(gè)事務(wù)中涉及到的多個(gè)操作在邏輯上缺一不可。事務(wù)的原子性要求事務(wù)中的所有操作要么都執(zhí)行,要么都不執(zhí)行。
  2. 一致性(consistency):“一致”指的是數(shù)據(jù)的一致,具體是指:所有數(shù)據(jù)都處于滿足業(yè)務(wù)規(guī)則的一致性狀態(tài)。一致性原則要求:一個(gè)事務(wù)中不管涉及到多少個(gè)操作,都必須保證事務(wù)執(zhí)行之前數(shù)據(jù)是正確的,事務(wù)執(zhí)行之后數(shù)據(jù)仍然是正確的。如果一個(gè)事務(wù)在執(zhí)行的過(guò)程中,其中某一個(gè)或某幾個(gè)操作失敗了,則必須將其他所有操作撤銷,將數(shù)據(jù)恢復(fù)到事務(wù)執(zhí)行之前的狀態(tài),這就是回滾。
  3. 隔離性(isolation):在應(yīng)用程序?qū)嶋H運(yùn)行過(guò)程中,事務(wù)往往是并發(fā)執(zhí)行的,所以很有可能有許多事務(wù)同時(shí)處理相同的數(shù)據(jù),因此每個(gè)事務(wù)都應(yīng)該與其他事務(wù)隔離開(kāi)來(lái),防止數(shù)據(jù)損壞。隔離性原則要求多個(gè)事務(wù)在并發(fā)執(zhí)行過(guò)程中不會(huì)互相干擾。
  4. 持久性(durability):持久性原則要求事務(wù)執(zhí)行完成后,對(duì)數(shù)據(jù)的修改永久的保存下來(lái),不會(huì)因各種系統(tǒng)錯(cuò)誤或其他意外情況而受到影響。通常情況下,事務(wù)對(duì)數(shù)據(jù)的修改應(yīng)該被寫入到持久化存儲(chǔ)器中。

1.2. 隔離級(jí)別

事務(wù)并發(fā)引起一些讀的問(wèn)題:

  • 臟讀:一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)未提交的數(shù)據(jù)
  • 不可重復(fù)讀: 一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)已提交的數(shù)據(jù) 單條記錄前后不匹配
  • 虛讀(幻讀: 一個(gè)事務(wù)可以讀取另一個(gè)事務(wù)已提交的數(shù)據(jù) 讀取的數(shù)據(jù)前后多了點(diǎn)或者少了點(diǎn)

并發(fā)寫:使用mysql默認(rèn)的鎖機(jī)制(獨(dú)占鎖)

解決讀問(wèn)題:設(shè)置事務(wù)隔離級(jí)別

  1. read uncommitted(0)
  2. read committed(2)
  3. repeatable read(4)
  4. Serializable(8)

隔離級(jí)別越高,性能越低。

一般情況下:臟讀是不可允許的,不可重復(fù)讀和幻讀是可以被適當(dāng)允許的。

1.3. 相關(guān)命令

查看全局事務(wù)隔離級(jí)別:SELECT @@global.tx_isolation

設(shè)置全局事務(wù)隔離級(jí)別:set global transaction isolation level read committed;

查看當(dāng)前會(huì)話事務(wù)隔離級(jí)別:SELECT @@tx_isolation

設(shè)置當(dāng)前會(huì)話事務(wù)隔離級(jí)別:set session transaction isolation level read committed;

查看mysql默認(rèn)自動(dòng)提交狀態(tài):select @@autocommit

設(shè)置mysql默認(rèn)自動(dòng)提交狀態(tài):set autocommit = 0;【不自動(dòng)提交】

開(kāi)啟一個(gè)事務(wù):start transaction;

提交事務(wù):commit

回滾事務(wù): rollback

在事務(wù)中創(chuàng)建一個(gè)保存點(diǎn):savepoint tx1

回滾到保存點(diǎn):rollback to tx1

1.4. 傳播行為

事務(wù)的傳播行為不是jdbc規(guī)范中的定義。傳播行為主要針對(duì)實(shí)際開(kāi)發(fā)中的問(wèn)題

1567660421239

七種傳播行為:

REQUIRED 支持當(dāng)前事務(wù),如果不存在,就新建一個(gè)

SUPPORTS 支持當(dāng)前事務(wù),如果不存在,就不使用事務(wù)

MANDATORY 支持當(dāng)前事務(wù),如果不存在,拋出異常

REQUIRES_NEW 如果有事務(wù)存在,掛起當(dāng)前事務(wù),創(chuàng)建一個(gè)新的事務(wù)

NOT_SUPPORTED 以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,掛起當(dāng)前事務(wù)

NEVER 以非事務(wù)方式運(yùn)行,如果有事務(wù)存在,拋出異常

NESTED 如果當(dāng)前事務(wù)存在,則嵌套事務(wù)執(zhí)行(嵌套式事務(wù))

  1. 依賴于JDBC3.0提供的SavePoint技術(shù)
  2. 刪除用戶 刪除訂單。在刪除訂單后,設(shè)置savePoint,執(zhí)行刪除用戶。刪除訂單和刪除用戶在同一事務(wù)中,刪除用戶失敗,事務(wù)回滾savePoint,由用戶控制視圖提交還是回滾

這七種事務(wù)傳播機(jī)制最常用的就兩種:

REQUIRED:一個(gè)事務(wù),要么成功,要么失敗

REQUIRES_NEW:兩個(gè)不同事務(wù),彼此之間沒(méi)有關(guān)系。一個(gè)事務(wù)失敗了不影響另一個(gè)事務(wù)

1.4.1. 偽代碼練習(xí)

傳播行為偽代碼模擬:有a,b,c,d,e等5個(gè)方法,a中調(diào)用b,c,d,e方法的傳播行為在小括號(hào)中標(biāo)出

a(required){
	b(required);
	c(requires_new);
	d(required);
	e(requires_new);
	// a方法的業(yè)務(wù)
}

問(wèn)題:

  1. a方法的業(yè)務(wù)出現(xiàn)異常,會(huì)怎樣?a,b,d回滾 c,e不回滾
  2. d方法出現(xiàn)異常,會(huì)怎樣?a,b,d回滾;c不回滾;e未執(zhí)行
  3. e方法出現(xiàn)異常,會(huì)怎樣?a,b,d,e回滾 c不回滾,e方法出異常會(huì)上拋影響到上級(jí)方法
  4. b方法出現(xiàn)異常,會(huì)怎樣?a,b回滾 c,d,e未執(zhí)行

加點(diǎn)難度:

a(required){
	b(required){
		f(requires_new);
		g(required)
	}
	c(requires_new){
		h(requires_new)
		i(required)
	}
	d(required);
	e(requires_new);
	// a方法的業(yè)務(wù)
}

問(wèn)題:

  1. a方法業(yè)務(wù)出異常?a,b,g,d回滾;f,c,h,i,e不回滾
  2. e方法出異常?e,a,b,g,d回滾;f,c,h,i不回滾
  3. d方法出異常?a,b,g,d回滾;f,c,h,i不回滾;e為執(zhí)行
  4. h,i方法分別出異常?h,i,c,a,b,g回滾;f不回滾;d,e未執(zhí)行
  5. i方法出異常?i,c,a,b,g回滾;f,h不回滾;d,e未執(zhí)行
  6. f,g方法分別出異常?f,g,b,a回滾;c,h,i,d,e未執(zhí)行

1.4.2. 改造商品新增代碼

現(xiàn)在商品保存的方法結(jié)構(gòu)如下:

    @Override
    public void bigSave(SpuVo spuVo) {
        /// 1.保存spu相關(guān)
        // 1.1. 保存spu基本信息 spu_info
        Long spuId = saveSpu(spuVo);

        // 1.2. 保存spu的描述信息 spu_info_desc
        saveSpuDesc(spuVo, spuId);

        // 1.3. 保存spu的規(guī)格參數(shù)信息
        saveBaseAttr(spuVo, spuId);

        /// 2. 保存sku相關(guān)信息
        saveSku(spuVo, spuId);
    }

    /**
     * 保存sku相關(guān)信息及營(yíng)銷信息
     * @param spuInfoVO
     */
    private void saveSku(SpuVo spuVo, Long spuId) { 。。。 }

    /**
     * 保存spu基本屬性信息
     * @param spuInfoVO
     */
    private void saveBaseAttr(SpuVo spuVo, Long spuId) { 。。。 }

    /**
     * 保存spu描述信息(圖片)
     * @param spuInfoVO
     */
    private void saveSpuDesc(SpuVo spuVo, Long spuId) { 。。。 }

    /**
     * 保存spu基本信息
     * @param spuInfoVO
     */
    private void saveSpu(SpuVo spuVo) {  。。。 }

為了測(cè)試事務(wù)傳播行為,我們?cè)赟puInfoService接口中把saveSkuInfoWithSaleInfo、saveBaseAttrs、saveSpuDesc、saveSpuInfo聲明為service接口方法。

public interface SpuInfoService extends IService<SpuInfoEntity> {

    PageVo queryPage(QueryCondition params);

    PageVo querySpuInfo(QueryCondition condition, Long catId);

    void saveSpuInfoVO(SpuInfoVO spuInfoVO);

    void saveSku(SpuVo spuVo, Long spuId);

    void saveBaseAttr(SpuVo spuVo, Long spuId);

    void saveSpuDesc(SpuVo spuVo, Long spuId);

    Long saveSpu(SpuVo spuVo);
}

再把SpuInfoServiceImpl實(shí)現(xiàn)類的對(duì)應(yīng)方法改成public:

1584780507279

1.4.3. 測(cè)試1:同一service + requires_new

springboot 1.x使用事務(wù)需要在引導(dǎo)類上添加**@EnableTransactionManagement注解開(kāi)啟事務(wù)支持**

springboot 2.x可直接使用**@Transactional**玩事務(wù),傳播行為默認(rèn)是REQUIRED

添加事務(wù):

1584784895102

這時(shí),在保存商品的主方法中制造異常:

1584784987731

由于保存商品描述方法使用的是requires_new,spu應(yīng)該會(huì)回滾,spu_desc應(yīng)該保存成功。

清空pms_spu_desc表,再添加一個(gè)spu保存。

結(jié)果pms_spu_desc表中依然沒(méi)有數(shù)據(jù)。

但是控制臺(tái)打印了新增pms_spu_desc表的sql語(yǔ)句:

1584791120439

說(shuō)明saveSpuDesc方法的事務(wù)回滾了,也就是說(shuō)該方法配置的事務(wù)傳播機(jī)制沒(méi)有生效。

解決方案:

把service方法放到不同的service中使用動(dòng)態(tài)代理對(duì)象調(diào)用該方法

1.4.4. 測(cè)試2:不同service + requires_new

把saveSpuDesc方法放到SpuDescService中:

1584791341509

在實(shí)現(xiàn)類中實(shí)現(xiàn)該方法,可以把之前的實(shí)現(xiàn)copy過(guò)來(lái):

1584791517742

改造SpuServiceImpl中保存商品的方法,調(diào)用SpuDescServiceImpl的saveSpuDesc方法:

1584791613579

再次重啟gmall-pms,雖然控制臺(tái)依然報(bào)錯(cuò),但是數(shù)據(jù)可以保存成功,說(shuō)明沒(méi)有在一個(gè)事務(wù)中。

1567687774435

為什么測(cè)試1的事務(wù)傳播行為沒(méi)有生效,而測(cè)試2的事務(wù)傳播行為生效了?

spring的事務(wù)是聲明式事務(wù),而聲明式事務(wù)的本質(zhì)是Spring AOP,SpringAOP的本質(zhì)是動(dòng)態(tài)代理。

事務(wù)要生效必須是代理對(duì)象在調(diào)用。

測(cè)試1:通過(guò)this調(diào)用同一個(gè)service中的方法,this是指service實(shí)現(xiàn)類對(duì)象本身,不是代理對(duì)象,就相當(dāng)于方法中的代碼粘到了大方法里面,相當(dāng)于還是一個(gè)方法。

測(cè)試2:通過(guò)其他service對(duì)象(spuDescService)調(diào)用,這個(gè)service對(duì)象本質(zhì)是動(dòng)態(tài)代理對(duì)象

接下來(lái)debug,打個(gè)斷點(diǎn)看看:

spuDescService:

1567689094127

this:

1567689136840

1.4.5. 在同一個(gè)service中使用傳播行為

只需要把測(cè)試1中的this.方法名()替換成this代理對(duì)象.方法名()即可。

問(wèn)題是怎么在service中獲取當(dāng)前類的代理對(duì)象?

在類中獲取代理對(duì)象分三個(gè)步驟:

  1. 導(dǎo)入aop的場(chǎng)景依賴:spring-boot-starter-aop
  2. 開(kāi)啟AspectJ的自動(dòng)代理,同時(shí)要暴露代理對(duì)象:@EnableAspectJAutoProxy(exposeProxy=true)
  3. 獲取代理對(duì)象:SpuInfoService proxy = (SpuInfoService) AopContext.currentProxy();

具體如下:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
        </dependency>

1567690207315

1567690368936

重啟后測(cè)試:先清空pms_spu_info_desc表中數(shù)據(jù)

1567690577522

表中數(shù)據(jù)新增成功,說(shuō)明saveSpuDesc方法走的是自己的事務(wù),傳播行為生效了。

debug可以看到,spuInfoService是一個(gè)代理對(duì)象。

1567690539055

1.5. 回滾策略

事務(wù)很重要的另一個(gè)特征是程序出異常時(shí),會(huì)回滾。但并不是所有的異常都會(huì)回滾。

默認(rèn)情況下的回滾策略:

  • 運(yùn)行時(shí)異常:不受檢異常,沒(méi)有強(qiáng)制要求try-catch,都會(huì)回滾。例如:ArrayOutOfIndex,OutofMemory,NullPointException
  • 編譯時(shí)異常:受檢異常,必須處理,要么try-catch要么throws,都不回滾。例如:FileNotFoundException

可以通過(guò)@Transactional注解的下面幾個(gè)屬性改變回滾策略:

1567670630801

  1. rollbackFor:指定的異常必須回滾
  2. noRollbackFor:發(fā)生指定的異常不用回滾

1.5.1. 測(cè)試編譯時(shí)異常不回滾

在商品保存方法中制造一個(gè)編譯時(shí)異常:

1584791955821

重啟測(cè)試,注意pms_spu表中數(shù)據(jù):

控制臺(tái)報(bào)異常:

1567691494892

pms_spu表中的數(shù)據(jù)新增成功了。

1567691611593

也就證明了編譯時(shí)異常不回滾。

1.5.2. 定制回滾策略

經(jīng)過(guò)剛才的測(cè)試,我們知道:

ArithmeticException異常(int i = 1/0)會(huì)回滾FileNotFoundException異常(new FileInputStream(“xxxx”))不回滾

接下來(lái)我們來(lái)改變一下這個(gè)策略:

1584792095693

測(cè)試:

FileNotFoundException:在程序中添加new FileInputStream(“xxxx”),然后測(cè)試。

1567692233983

還是id還是17,說(shuō)明回滾了(回滾也會(huì)占用id=18)

ArithmeticException:在程序中添加int i = 1/0; 然后測(cè)試。

1567692364759

id是19,說(shuō)明沒(méi)有回滾。

1.6. 超時(shí)事務(wù)

@Transactional注解,還有一個(gè)屬性是timeout超時(shí)時(shí)間,單位是秒。

1567692523018

timeout=3:是指第一個(gè)sql開(kāi)始執(zhí)行到最后一個(gè)sql結(jié)束執(zhí)行之間的間隔時(shí)間。

即:超時(shí)時(shí)間(timeout)是指數(shù)據(jù)庫(kù)超時(shí),不是業(yè)務(wù)超時(shí)。

改造之前商品保存方法:SpuInfoServiceImpl類中

1584792229794

重啟測(cè)試:控制臺(tái)出現(xiàn)事務(wù)超時(shí)異常

1567693383569

1.7. 只讀事務(wù)

@Transactional注解最后一個(gè)屬性是只讀事務(wù)屬性

1567693468270

如果一個(gè)方法標(biāo)記為readOnly=true事務(wù),則代表該方法只能查詢,不能增刪改。readOnly默認(rèn)為false

給商品新增的事務(wù)標(biāo)記為只讀事務(wù):

1584792311622

測(cè)試:

1567693694019

到此這篇關(guān)于spring boot本地事務(wù)@Transactional參數(shù)詳解的文章就介紹到這了,更多相關(guān)spring boot事務(wù)Transactional內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java生成Jar包方法步驟

    Java生成Jar包方法步驟

    在Java開(kāi)發(fā)中,打包成JAR文件是一種常見(jiàn)的方式,本文主要介紹了Java生成Jar包方法步驟,具有一定的參考價(jià)值,感興趣的可以了解一下
    2023-10-10
  • SpringBoot將所有依賴(包括本地jar包)打包到項(xiàng)目

    SpringBoot將所有依賴(包括本地jar包)打包到項(xiàng)目

    這篇文章主要介紹了SpringBoot將所有依賴(包括本地jar包)打包到項(xiàng)目,本文通過(guò)示例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2023-06-06
  • java模擬多線程http請(qǐng)求代碼分享

    java模擬多線程http請(qǐng)求代碼分享

    本篇文章給大家分享了java模擬多線程http請(qǐng)求的相關(guān)實(shí)例代碼,對(duì)此有需要的可以跟著測(cè)試下。
    2018-05-05
  • Java中的HashMap集合源碼詳細(xì)解讀

    Java中的HashMap集合源碼詳細(xì)解讀

    這篇文章主要介紹了Java中的HashMap集合源碼詳細(xì)解讀,hash表是一種數(shù)據(jù)結(jié)構(gòu),它擁有驚人的效率,它的時(shí)間復(fù)雜度低到接近O(1)這樣的常數(shù)級(jí),需要的朋友可以參考下
    2023-11-11
  • Java單例模式簡(jiǎn)單示例

    Java單例模式簡(jiǎn)單示例

    這篇文章主要介紹了Java單例模式,結(jié)合實(shí)例形式簡(jiǎn)單分析了java單例模式的定義與使用技巧,需要的朋友可以參考下
    2017-06-06
  • java操作cookie示例(刪除cookie)

    java操作cookie示例(刪除cookie)

    這篇文章主要介紹了java操作cookie示例,包括設(shè)置Cookie、讀取Cookie、刪除Cookie,需要的朋友可以參考下
    2014-02-02
  • Java8新特性詳解與實(shí)戰(zhàn)分享

    Java8新特性詳解與實(shí)戰(zhàn)分享

    Java 8作為Java語(yǔ)言的一個(gè)重要更新,引入了一系列新特性,這些特性不僅提高了代碼的可讀性和可維護(hù)性,還增強(qiáng)了程序的性能,本文將詳細(xì)介紹Java 8中的幾個(gè)關(guān)鍵使用技巧,并通過(guò)代碼案例來(lái)展示它們的應(yīng)用,需要的朋友可以參考下
    2024-06-06
  • Springboot+hibernate實(shí)現(xiàn)簡(jiǎn)單的增刪改查示例

    Springboot+hibernate實(shí)現(xiàn)簡(jiǎn)單的增刪改查示例

    今天小編就為大家分享一篇Springboot+hibernate實(shí)現(xiàn)簡(jiǎn)單的增刪改查示例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-08-08
  • MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題

    MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題

    這篇文章主要介紹了MyBatisPlus自定義JsonTypeHandler實(shí)現(xiàn)自動(dòng)轉(zhuǎn)化JSON問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-12-12
  • SpringBoot自動(dòng)配置之自定義starter的實(shí)現(xiàn)代碼

    SpringBoot自動(dòng)配置之自定義starter的實(shí)現(xiàn)代碼

    這篇文章主要介紹了SpringBoot自動(dòng)配置之自定義starter的實(shí)現(xiàn)代碼,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-10-10

最新評(píng)論

遵义市| 伊春市| 秭归县| 武陟县| 齐齐哈尔市| 海原县| 盐山县| 石林| 石林| 凭祥市| 通山县| 白水县| 玉林市| 峨山| 南阳市| 神池县| 长子县| 灵石县| 灵武市| 筠连县| 邵东县| 汉阴县| 合山市| 宁夏| 留坝县| 长汀县| 合江县| 双柏县| 阿拉善右旗| 盘锦市| 建宁县| 治县。| 昌江| 诏安县| 松滋市| 通渭县| 景洪市| 龙里县| 苍溪县| 闵行区| 民勤县|