成人免费xxxxx在线视频软件_久久精品久久久_亚洲国产精品久久久_天天色天天色_亚洲人成一区_欧美一级欧美三级在线观看

再深一點(diǎn):面試工作兩不誤,源碼級理解Spring事務(wù)

開發(fā) 架構(gòu)
Spring有5種隔離級別,7種傳播行為。這是面試常問的內(nèi)容,也是代碼中經(jīng)常碰到的知識點(diǎn)。這些知識枯燥而且乏味,其中有些非常的繞。如果栽在這上面,就實(shí)在是太可惜了。

 Spring有5種隔離級別,7種傳播行為。這是面試常問的內(nèi)容,也是代碼中經(jīng)常碰到的知識點(diǎn)。這些知識枯燥而且乏味,其中有些非常的繞。如果栽在這上面,就實(shí)在是太可惜了。

 

xjjdog在一些事務(wù)的基礎(chǔ)上,再探討幾個容易淡忘的概念,從源碼層面找原因,加深我們的理解,問題大概包括:

  1. Spring的事務(wù)和數(shù)據(jù)庫的事務(wù)隔離是一個概念么?
  2. Spring是如何實(shí)現(xiàn)事務(wù)的?
  3. 事務(wù)隔離機(jī)制都有哪些?
  4. 事務(wù)傳播機(jī)制都有哪些?
  5. 查詢語句需要開事務(wù)么?
  6. private方法加事務(wù)注解有用么?

1、Spring的事務(wù)和數(shù)據(jù)庫的事務(wù)隔離是一個概念么?

先來第一個問題,Spring的事務(wù)隔離級別和數(shù)據(jù)的事務(wù)隔離級別,是一回事么?

其實(shí),數(shù)據(jù)庫一般只有4種隔離機(jī)制,Spring抽象出一種default,根據(jù)數(shù)據(jù)設(shè)置來變動。

 

  • read uncommitted(未提交讀)
  • read committed(提交讀、不可重復(fù)讀)
  • repeatable read(可重復(fù)讀)
  • serializable(可串行化)
  • default (PlatformTransactionManager默認(rèn)的隔離級別,使用的就是數(shù)據(jù)庫默認(rèn)的)

這是因?yàn)椋琒pring只提供統(tǒng)一事務(wù)管理接口,具體實(shí)現(xiàn)都是由各數(shù)據(jù)庫自己實(shí)現(xiàn)(如MySQL)。Spring會在事務(wù)開始時,根據(jù)當(dāng)前環(huán)境中設(shè)置的隔離級別,調(diào)整數(shù)據(jù)庫隔離級別,由此保持一致。

在DataSourceUtils文件中,代碼詳細(xì)的輸出了這個過程。

  1. // Apply specific isolation level, if any
  2. Integer previousIsolationLevel = null
  3. if (definition != null && definition.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT) { 
  4.     if (logger.isDebugEnabled()) { 
  5.         logger.debug("Changing isolation level of JDBC Connection [" + con + "] to " + 
  6.                 definition.getIsolationLevel()); 
  7.     } 
  8.     int currentIsolation = con.getTransactionIsolation(); 
  9.     if (currentIsolation != definition.getIsolationLevel()) { 
  10.         previousIsolationLevel = currentIsolation; 
  11.         con.setTransactionIsolation(definition.getIsolationLevel()); 
  12.     } 

結(jié)論:三種情況,如果Spring沒有指定事務(wù)隔離級別,則會采用數(shù)據(jù)庫默認(rèn)的事務(wù)隔離級別;當(dāng)Spring指定了事務(wù)隔離級別,則會在代碼里將事務(wù)隔離級別修改為指定值;當(dāng)數(shù)據(jù)庫不支持這種隔離級別,效果則以數(shù)據(jù)庫的為準(zhǔn)(比如采用了MyISAM引擎)。

我們會使用如下的方式進(jìn)行聲明。如果不是有性能和需求問題,就不要瞎改。事務(wù)處理弄不好是會鎖表的,而鎖表在大并發(fā)的情況下是會死人的。

  1. @Transactional(isolation = Isolation.READ_UNCOMMITTED) 

2、Spring事務(wù)的7種傳播機(jī)制

只要寫代碼,代碼總會存在嵌套,或者循環(huán),造成了事務(wù)的嵌套或者循環(huán)。那么事務(wù)在這些情況下,根據(jù)配置會有不同的反應(yīng)。

 

  • REQUIRED 這是默認(rèn)的。表示當(dāng)前方法必須在一個具有事務(wù)的上下文中運(yùn)行,如有客戶端有事務(wù)在進(jìn)行,那么被調(diào)用端將在該事務(wù)中運(yùn)行,否則的話重新開啟一個事務(wù)。(如果被調(diào)用端發(fā)生異常,那么調(diào)用端和被調(diào)用端事務(wù)都將回滾)
  • REQUIRE_NEW 表示當(dāng)前方法必須運(yùn)行在它自己的事務(wù)中。如果存在當(dāng)前事務(wù),在該方法執(zhí)行期間,當(dāng)前事務(wù)會被掛起
  • NESTED 如果當(dāng)前方法正有一個事務(wù)在運(yùn)行中,則該方法應(yīng)該運(yùn)行在一個嵌套事務(wù)中,被嵌套的事務(wù)可以獨(dú)立于被封裝的事務(wù)中進(jìn)行提交或者回滾。如果封裝事務(wù)存在,并且外層事務(wù)拋出異常回滾,那么內(nèi)層事務(wù)必須回滾,反之,內(nèi)層事務(wù)并不影響外層事務(wù)。如果封裝事務(wù)不存在,則同required的一樣
  • SUPPORTS 表示當(dāng)前方法不必需要具有一個事務(wù)上下文,但是如果有一個事務(wù)的話,它也可以在這個事務(wù)中運(yùn)行
  • NOT_SUPPORTED 表示該方法不應(yīng)該在一個事務(wù)中運(yùn)行。如果有一個事務(wù)正在運(yùn)行,他將在運(yùn)行期被掛起,直到這個事務(wù)提交或者回滾才恢復(fù)執(zhí)行
  • MANDATORY 表示當(dāng)前方法必須在一個事務(wù)中運(yùn)行,如果沒有事務(wù),將拋出異常
  • NEVER 表示當(dāng)方法務(wù)不應(yīng)該在一個事務(wù)中運(yùn)行,如果存在一個事務(wù),則拋出異常

一般用得比較多的是REQUIRED , REQUIRES_NEW,用到其他的,你就要小心了,搞懂再用。

最怕如果這倆字了,它會將事情搞的很復(fù)雜,尤其是代碼量大的時候,你永遠(yuǎn)不知道你寫的service會被誰用到。這就很尷尬了。

我們會采用下面的方式進(jìn)行聲明。鑒于Spring的事務(wù)傳播非常的繞,如果功能滿足需求,那么就用默認(rèn)的就好,否則會引起不必要的麻煩。

  1. @Transactional(propagation=Propagation.REQUIRED) 

3、事務(wù)傳播機(jī)制是怎么實(shí)現(xiàn)的?

事務(wù)傳播機(jī)制看似神奇,實(shí)際上是使用簡單的ThreadLocal的機(jī)制實(shí)現(xiàn)的。所以,如果調(diào)用的方法是在新線程調(diào)用的,事務(wù)傳播實(shí)際上是會失效的。這不同于我們以前講到的透傳,Spring并沒有做這樣的處理。

所以事務(wù)傳播機(jī)制,只有翻一遍源代碼,才能印象深刻。僅靠文字去傳播,很多東西會變得不可描述。

 

如圖,PlatformTransactionManager只有簡單的三個抽象接口,定義了包含JDBC在內(nèi)的Spring所有的事務(wù)操作。

 

我們平常說的JDBC,只是占到其中一部分。

實(shí)現(xiàn)的方式,依然是使用AOP來實(shí)現(xiàn)的,具體的實(shí)現(xiàn)類是由TransactionAspectSupport來實(shí)現(xiàn)的。可以看到,代碼定義了一個叫做transactionInfoHolder的ThreadLocal變量,當(dāng)用到它的時候,就能夠確保在同一個線程下,獲取的變量是一致的。

  1. /** 
  2.     * Holder to support the {@code currentTransactionStatus()} method, 
  3.     * and to support communication between different cooperating advices 
  4.     * (e.g. before and after advice) if the aspect involves more than a 
  5.     * single method (as will be the case for around advice). 
  6. */ 
  7. private static final ThreadLocal<TransactionInfo> transactionInfoHolder = 
  8.         new NamedThreadLocal<>("Current aspect-driven transaction"); 

具體的業(yè)務(wù)邏輯,是在invokeWithinTransaction中實(shí)現(xiàn)的。如果你繼續(xù)向下跟蹤的話,會找到AbstractPlatformTransactionManager類中的getTransaction方法。

  1. @Override 
  2. public final TransactionStatus getTransaction(@Nullable TransactionDefinition definition) 
  3.         throws TransactionException { 
  4.  
  5.  
  6.     // Use defaults if no transaction definition given. 
  7.     TransactionDefinition def = (definition != null ? definition : TransactionDefinition.withDefaults()); 
  8.  
  9.  
  10.     Object transaction = doGetTransaction(); 
  11.     boolean debugEnabled = logger.isDebugEnabled(); 
  12.  
  13.  
  14.     if (isExistingTransaction(transaction)) { 
  15.         // Existing transaction found -> check propagation behavior to find out how to behave. 
  16.         return handleExistingTransaction(def, transaction, debugEnabled); 
  17.     } 
  18.  
  19.  
  20.     // Check definition settings for new transaction
  21.     if (def.getTimeout() < TransactionDefinition.TIMEOUT_DEFAULT) { 
  22.         throw new InvalidTimeoutException("Invalid transaction timeout", def.getTimeout()); 
  23.     } 
  24.  
  25.  
  26.     // No existing transaction found -> check propagation behavior to find out how to proceed. 
  27.     if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_MANDATORY) { 
  28.         throw new IllegalTransactionStateException( 
  29.                 "No existing transaction found for transaction marked with propagation 'mandatory'"); 
  30.     } 
  31.     else if (def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRED || 
  32.             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_REQUIRES_NEW || 
  33.             def.getPropagationBehavior() == TransactionDefinition.PROPAGATION_NESTED) { 
  34.         SuspendedResourcesHolder suspendedResources = suspend(null); 
  35.         if (debugEnabled) { 
  36.             logger.debug("Creating new transaction with name [" + def.getName() + "]: " + def); 
  37.         } 
  38.         try { 
  39.             return startTransaction(def, transaction, debugEnabled, suspendedResources); 
  40.         } 
  41.         catch (RuntimeException | Error ex) { 
  42.             resume(null, suspendedResources); 
  43.             throw ex; 
  44.         } 
  45.     } 
  46.     else { 
  47.         // Create "empty" transactionno actual transaction, but potentially synchronization. 
  48.         if (def.getIsolationLevel() != TransactionDefinition.ISOLATION_DEFAULT && logger.isWarnEnabled()) { 
  49.             logger.warn("Custom isolation level specified but no actual transaction initiated; " + 
  50.                     "isolation level will effectively be ignored: " + def); 
  51.         } 
  52.         boolean newSynchronization = (getTransactionSynchronization() == SYNCHRONIZATION_ALWAYS); 
  53.         return prepareTransactionStatus(def, nulltrue, newSynchronization, debugEnabled, null); 
  54.     } 

不用我做過多解釋了吧,一切明顯的邏輯,都在代碼里。事務(wù)就是在這里創(chuàng)建的。

4、查詢方法可以不開啟事務(wù)么?

事務(wù)有個readonly,控制了事務(wù)的只讀屬性,和事務(wù)是否開啟沒半毛錢關(guān)系。

在以前的一篇文章中,談到通過設(shè)置readonly屬性來控制語句的路由:”MySQL官方驅(qū)動“主從分離的神秘面紗(掃盲篇),這其中就用到了事務(wù)的其中一個屬性readonly,它最終是體現(xiàn)在數(shù)據(jù)庫連接層面的。

  1. connection.setReadOnly(true); 

在Spring中的使用方式如下:

  1. @Transactional(readOnly=true

值得注意的是,這個屬性設(shè)置之后,并不是每個底層的數(shù)據(jù)庫都支持。中間層的ORM或者驅(qū)動,也可能會拿這個屬性做一些文章,所以與其說這個readonly是功能性的,不如說是一種暗示。

拿MySQL來說,有兩種提交模式:

  • SET AUTOCOMMIT=0 禁止自動提交
  • SET AUTOCOMMIT=1 開啟自動提交

這都是實(shí)打?qū)嵉腟QL語句,所以如果開啟了事務(wù),AUTOCOMMIT要為false。我們可以看到Spring做了以下幾個操作。

  1. con.setAutoCommit(false); 

如果是只讀事務(wù),還不忘手動設(shè)置一下。

  1. if (isEnforceReadOnly() && definition.isReadOnly()) {    try (Statement stmt = con.createStatement()) { 
  2.         stmt.executeUpdate("SET TRANSACTION READ ONLY"); 
  3.     } 

這種操作是很昂貴的,如果不加Transaction注解,默認(rèn)是不開啟事務(wù)的。單條的查詢語句也是沒有必要開啟事務(wù)的,數(shù)據(jù)庫默認(rèn)的配置就能滿足需求。

但如果你一次執(zhí)行多條查詢語句,例如統(tǒng)計(jì)查詢,報(bào)表查詢,在這種場景下,多條查詢SQL必須保證整體的讀一致性,否則,在前條SQL查詢之后,后條SQL查詢之前,數(shù)據(jù)被其他用戶改變,就會造成數(shù)據(jù)的前后不一。

也僅有在這種情況下,要開啟讀事務(wù)。

5、private方法加事務(wù)注解有用么?

@Transaction注解加在private上,并沒有什么卵用。

這倒不是事務(wù)處理的代碼去寫的特性。由于事務(wù)的這些功能,是通過AOP方式強(qiáng)加進(jìn)去的,所以它收到動態(tài)代理的控制。

private和final修飾的方法,不會被代理。

但是,你卻可以把private方法放在帶有事務(wù)功能的public方法里。這樣,它看起來也有了事務(wù)的一些功能特性,但它并沒有。

End

互聯(lián)網(wǎng)中,用到的事務(wù)并不多,很多都是非常小、速度非常快的接口,對于開發(fā)人員來說,事務(wù)是個累贅。

但在一些帶有金融屬性的業(yè)務(wù)中,或者一些企業(yè)級開發(fā)應(yīng)用中,事務(wù)確實(shí)一個繞不過的坎。一旦深入其中,就會發(fā)現(xiàn)這個知識點(diǎn),露著血盆大口,等君入甕。

xjjdog從源碼層次,聊到了幾個面試常問的問題。不要覺得奇怪,有的人確實(shí)一直在拿著臟讀、幻讀這樣的名詞來面試。

而這些東西,都屬于當(dāng)時看了恍然大悟,第二天就繼續(xù)懵逼的內(nèi)容。

什么時候,才能務(wù)實(shí)一點(diǎn)呢?

作者簡介:小姐姐味道 (xjjdog),一個不允許程序員走彎路的公眾號。聚焦基礎(chǔ)架構(gòu)和Linux。十年架構(gòu),日百億流量,與你探討高并發(fā)世界,給你不一樣的味道。我的個人微信xjjdog0,歡迎添加好友,進(jìn)一步交流

責(zé)任編輯:武曉燕 來源: 小姐姐味道
相關(guān)推薦

2020-09-01 07:36:29

分布式鎖分布式進(jìn)程

2009-02-10 09:33:00

DNS網(wǎng)絡(luò)訪問

2014-06-20 19:07:54

云存儲聯(lián)想企業(yè)網(wǎng)盤

2010-01-13 08:55:31

Windows 7音頻播放

2011-10-08 12:21:19

華碩臺式機(jī)

2015-04-27 13:29:24

2013-06-03 17:17:14

Android開發(fā)Android程序Android手機(jī)平板

2022-01-26 00:41:58

程序員學(xué)習(xí)型工作

2009-04-03 08:22:40

聯(lián)想楊元慶拳擊手

2016-08-26 13:51:50

聯(lián)想系統(tǒng)搬遷服

2015-10-29 17:58:57

安全WiFi瑞星

2016-07-07 17:29:40

企業(yè)辦公

2010-05-25 14:11:49

酷睿I3HTPC

2012-04-19 15:52:29

投影機(jī)推薦

2009-04-28 11:19:17

電腦保險(xiǎn)PICC金山毒霸

2025-02-13 08:36:52

2014-06-23 14:31:34

信鴿企業(yè)IM

2020-08-18 11:26:57

巴菲特韭菜股票

2011-10-26 11:26:27

筆記本評測
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

主站蜘蛛池模板: 国产91av视频在线观看 | 欧美精品v国产精品v日韩精品 | 久久国产区 | 午夜精品久久久久久久 | 喷潮网站| 亚洲国产视频一区二区 | 性色综合| 九九热精品视频 | 成人毛片视频免费 | www.国产一区 | 日韩一级精品视频在线观看 | 日韩中文字幕在线播放 | 日皮视频免费 | 国产一区二区三区视频在线观看 | 91视视频在线观看入口直接观看 | 欧美日韩成人在线 | 久久婷婷国产 | 日本黄色一级片视频 | 亚洲精品一区中文字幕乱码 | 国产精品一区二区久久久久 | 亚洲区一 | 久久99精品久久久久久琪琪 | 伊伊综合网 | 国产在线精品一区 | 国产视频1 | 欧美在线观看免费观看视频 | 国产乱码精品一区二区三区五月婷 | 在线视频中文字幕 | 一a级片 | 日本精品一区二区三区在线观看 | 国产一区二区在线视频 | 久久这里只有 | 日韩欧美中文字幕在线观看 | 国产伦一区二区三区视频 | 亚洲 中文 欧美 日韩 在线观看 | 国产精品伦一区二区三级视频 | 日韩毛片在线视频 | 狠狠的干 | 久久久精品影院 | 色婷婷综合久久久中字幕精品久久 | 区一区二在线观看 |