日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網為廣大站長提供免費收錄網站服務,提交前請做好本站友鏈:【 網站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(50元/站),

點擊這里在線咨詢客服
新站提交
  • 網站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

AQS到底有什么用?難道就真的只是為了面試嗎?

當然不是說AQS沒用,如果你不是做基礎架構或者中間件開發,你很難感受到AQS的威力。當然,學習很多時候,需要的是正向反饋,學了太多造火箭的東西,面試完就再也用不上,自然很難有動力保持持續學習。那么,有沒有受眾群體大,就算平時CRUD的同學也用得到,同時面試又喜歡問,最重要的是,出問題的時候,搜索還不容易搜索出答案的知識點?

那么,這個就是肥朝之前提到的Spring事務傳播機制。

為啥是Spring事務傳播機制?

原因很簡單,因為能滿足上述三個條件的,第一個想到的,就是Spring事務傳播機制,他具備了幾個條件

1.CRUD的同學,平時和事務打交道最多。并且,事務一旦出了問題,那可是爆炸性的傷害,這點毋容置疑

2.面試高頻考點,一般還會問數據庫的隔離級別。但是肥朝發現,很多同學把數據庫的隔離級別和Spring的事務傳播機制這兩個概念搞混,其實這是兩碼事。同時,也有比較出名的面試題,"做51次操作,前面50次成功,第51次失敗,如何把前面成功的50次提交,第51次失敗的回滾"。如果你對Spring的事務傳播機制不了解,那么你對于這個問題,是沒有什么頭緒的,原因在于,很多同學平時只處理過,全部提交和全部回滾兩個情況。

3.即使你在別的地方看過類似的Spring事務傳播機制的文章,對于常規的情況是沒問題,但是如果在多個try模型下,你對于是否能回滾,心里還是沒底的,說白了,就是你還是沒能摸透原理!

4.最重要的當然是肥朝之前答應過大家要寫這篇,不想做渣男。

 

 

 

基本概念

Spring的事務傳播機制有以下七種

PROPAGATION_REQUIRED:Spring的默認傳播級別,如果上下文中存在事務則加入當前事務,如果不存在事務則新建事務執行。

PROPAGATION_SUPPORTS:如果上下文中存在事務則加入當前事務,如果沒有事務則以非事務方式執行。

PROPAGATION_MANDATORY:該傳播級別要求上下文中必須存在事務,否則拋出異常。

PROPAGATION_REQUIRES_NEW:該傳播級別每次執行都會創建新事務,并同時將上下文中的事務掛起,執行完當前線程后再恢復上下文中事務。(子事務的執行結果不影響父事務的執行和回滾)

PROPAGATION_NOT_SUPPORTED:當上下文中有事務則掛起當前事務,執行完當前邏輯后再恢復上下文事務。(降低事務大小,將非核心的執行邏輯包裹執行。)

PROPAGATION_NEVER:該傳播級別要求上下文中不能存在事務,否則拋出異常。

PROPAGATION_NESTED:嵌套事務,如果上下文中存在事務則嵌套執行,如果不存在則新建事務。(save point概念)

看完這七種是不是云里霧里?那就對了!坦白說,這七種你記得住,其實也沒多大意義,記得住多半也是背下來的。其中PROPAGATION_REQUIRED這種默認的情況,是我們用得最多的,基本覆蓋90%的情況,也就是大家常見的,一起回滾的情況。還有一個是PROPAGATION_REQUIRES_NEW。基本你把這兩個掌握了,應對95%的情況一點兒問題都沒有,如果還有問題,你再來查這七種,找到你合適的。

例題講解

如果只是羅列概念,那意義不大,因此我們采用應試教育的方式來做題,才是檢驗掌握程度比較好的做法

案例一:常規情況

這種也是大家最常見的情況

@Transactional
@Override
public void Example1(User user) {
    userMApper.insert(user);
    propagationService.required();
}
@Transactional
@Override
public void required() {
    throw new NullPointerException;
}

單元測試

@Test
public void testExample1() throws Exception {
    User user = new User();
    user.setName;
    userService.Example1(user);
}

案例二:try-required

開始敲黑板劃重點了,這個情況也是大家最常見的情況之一,但是由于這個try起來了,異常不會拋出,那么,這個insert能否插入數據呢?

@Transactional
@Override
public void Example2(User user) {
    userMapper.insert(user);
    try {
        propagationService.required();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
@Transactional
@Override
public void required() {
    throw new NullPointerException;
}

單元測試

@Test
public void testExample2() throws Exception {
    User user = new User();
    user.setName;
    userService.Example2(user);
}

案例三:try-requiresNew

這個案例和上面的案例很相似,區別在于,這里的隔離級別是Propagation.REQUIRES_NEW,那么,這個insert能否插入數據呢?

@Transactional
@Override
public void Example3(User user) {
    userMapper.insert(user);
    try {
        propagationService.requiresNew();
    } catch (Exception e) {
        e.printStackTrace();
    }
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void requiresNew() {
    throw new NullPointerException;
}

單元測試

@Test
public void testExample3() throws Exception {
    User user = new User();
    user.setName;
    userService.Example3(user);
}

案例四:常規情況

這個和案例一很想,結果會有差別嗎?最后insert能插入嗎?

@Transactional
@Override
public void Example4(User user) {
    userMapper.insert(user);
    propagationService.requiresNew();
}
@Transactional(propagation = Propagation.REQUIRES_NEW)
@Override
public void requiresNew() {
    throw new NullPointerException;
}

單元測試

@Test
public void testExample4() throws Exception {
    User user = new User();
    user.setName;
    userService.Example4(user);
}

解密及大白話說明原理

案例一

這個不用說,稍微有點JAVA常識的人都知道,異常必然會導致回滾,數據庫不會插入數據。

案例二

這個到底會不會插入數據呢?畢竟這個異常被try起來了。這個時候,正常的思維都會認為,能正常插入數據,但是答案是,不會插入數據,并且拋出異常

org.springframework.transaction.UnexpectedRollbackException: Transaction rolled back because it has been marked as rollback-only

為啥會這樣呢?

案例三

這個和案例二很像,因為有了案例二的陰影,這個時候你就變得不確定了。答案是,能正常插入數據。

案例四

這個和案例一很像,本來你是很確定能不能插入數據的,但是有了案例三的陰影之后,這個時候你又變得不確定了。答案是,不會插入數據。

原理!

這四個案例,只要你把這四個案例和原理弄熟,再復雜的各種try模型下,事務是否回滾,你都清清楚楚。

我們先來看看@Transactional的核心方法

	if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
		// 開啟事務
		TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
		Object retVal = null;
		try {
			// 執行業務方法
			retVal = invocation.proceedWithInvocation();
		}
		catch (Throwable ex) {
			// 回滾事務
			completeTransactionAfterThrowing(txInfo, ex);
			throw ex;
		}
		finally {
			cleanupTransactionInfo(txInfo);
		}
		// 提交事務
		commitTransactionAfterReturning(txInfo);
		return retVal;
	}

我們重點解析案例二和案例三的情況。我們再把那兩個事務傳播機制的意思來解讀一下:

PROPAGATION_REQUIRED:Spring的默認傳播級別,如果上下文中存在事務則加入當前事務,如果不存在事務則新建事務執行。

PROPAGATION_REQUIRES_NEW:該傳播級別每次執行都會創建新事務,并同時將上下文中的事務掛起,執行完當前線程后再恢復上下文中事務。

首先來看案例二,執行Example2方法的時候,由上文得知,將開啟一個事務,再執行到required方法時,此時,因為用得的默認的隔離級別,因此,這個時候,會加入到剛才的事務之中,然后required方法中,出現了異常,我們來看

completeTransactionAfterThrowing(txInfo, ex);

中的核心方法

Java程序員只會CRUD連Spring事務傳播機制都不懂?

 

從doSetRollbackOnly(status)這個單詞就知道,required的時候,已經把這個事務設置成RollbackOnly,因此,雖然try住了,但是Example2執行完提交的時候,卻發現無法提交,所以異常信息如下:

Transaction rolled back because it has been marked as rollback-only

一圖勝千言,我用一張圖來描述這個關系

 

Java程序員只會CRUD連Spring事務傳播機制都不懂?

 

那為啥案例三,又能插入數據呢?還是用一張圖來描述

Java程序員只會CRUD連Spring事務傳播機制都不懂?

 

需要注意

@Transactional有很多注意點

  • 在同個類中調用A方法調用B方法,B方法是不會開啟事務,自然也就不會用到事務的傳播機制。這個原理后續肥朝會解析,當然如果你連這句話都不知道是什么意思,假粉實錘了!
  • @Transactional默認情況下,只回滾RuntimeException。如果你拋出的異常不是RuntimeException,可能導致在默認情況下和本文有所偏差

當然,這么多注意點,哪記得住,因此,留意后續的原理解析,就非常有必要了。

 

分享到:
標簽:程序員
用戶無頭像

網友整理

注冊時間:

網站:5 個   小程序:0 個  文章:12 篇

  • 51998

    網站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網站吧!
最新入駐小程序

數獨大挑戰2018-06-03

數獨一種數學游戲,玩家需要根據9

答題星2018-06-03

您可以通過答題星輕松地創建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學四六

運動步數有氧達人2018-06-03

記錄運動步數,積累氧氣值。還可偷

每日養生app2018-06-03

每日養生,天天健康

體育訓練成績評定2018-06-03

通用課目體育訓練成績評定