是什么、為什么、怎么樣這大概是所有問題必經之路,也是我們解決問題的思路,
- 什么是 IoC?
- IoC 解決了什么問題?
- IoC 和 DI 的區別?
- 什么是 AOP?
- AOP 解決了什么問題?
- AOP 為什么叫做切面編程?

什么是IOC?
IoC (Inversion of control )控制反轉/反轉控制,它是一種思想不是一個技術實作,描述的是:Java 開發領域物件的創建以及管理的問題,
ioc的思想最核心的地方在于,資源不由使用資源的雙方管理,而由不使用資源的第三方管理,Spring IOC則是第三方,用于物件的創建以及管理,
要了解控制反轉IOC我覺得有必要先了解軟體設計的一個重要思想:依賴倒置原則——把原本的高層建筑依賴底層建筑“倒置”過來,變成底層建筑依賴高層建筑,高層建筑決定需要什么,底層去實作這樣的需求,但是高層并不用管底層是怎么實作的,這樣就不會出現前面的“牽一發動全身”的情況

IoC 最常見以及最合理的實作方式叫做依賴注入(Dependency Injection,簡稱 DI),
控制反轉是目的,依賴注入是實作控制反轉的手段,
何為依賴,依賴什么?
程式運行需要依賴外部的資源,提供程式內物件的所需要的資料、資源,應用程式依賴于IoC容器,
何為注入,注入什么?
組態檔把資源從外部注入到內部,容器加載了外部的檔案、物件、資料,然后把這些資源注入給程式內的物件,維護了程式內外物件之間的依賴關系,
所以說,控制反轉是通過依賴注入實作的,像是「從不同角度描述的同一件事」:
- IoC 是設計思想,DI 是具體的實作方式;
- IoC 是理論,DI 是實踐;
從而實作物件之間的解藕,
當然,IoC 也可以通過其他的方式來實作,而 DI 只是 Spring 的選擇,

為什么叫控制反轉
控制 :指的是物件創建(實體化、管理)的權力
反轉 :控制權交給外部環境(Spring 框架、IoC 容器)
●誰控制誰,控制什么:傳統Java SE程式設計,我們直接在物件內部通過new進行創建物件,是程式主動去創建依賴物件;而IoC是有專門一個容器來創建這些物件,即由Ioc容器來控制物件的創建;誰控制誰?當然是IoC 容器控制了物件;控制什么?那就是主要控制了外部資源獲取(不只是物件包括比如檔案等),
●為何是反轉,哪些方面反轉了:有反轉就有正轉,傳統應用程式是由我們自己在物件中主動控制去直接獲取依賴物件,也就是正轉;而反轉則是由容器來幫忙創建及注入依賴物件;為何是反轉?因為由容器幫我們查找及注入依賴物件,物件只是被動的接受依賴物件,所以是反轉;哪些方面反轉了?依賴物件的獲取被反轉了,
IoC 解決了什么問題?
IoC 的思想就是兩方之間不互相依賴,由第三方容器來管理相關資源,這樣有什么好處呢?
解耦:物件之間的耦合度或者說依賴程度降低;
管理:資源變的容易管理;比如你用 Spring 容器提供的話很容易就可以實作一個單例,
將物件之間的相互依賴關系交給 IoC 容器來管理,并由 IoC 容器完成物件的注入,這樣可以很大程度上簡化應用的開發,把應用從復雜的依賴關系中解放出來, IoC 容器就像是一個工廠一樣,當我們需要創建一個物件的時候,只需要配置好組態檔/注解即可,完全不用考慮物件是如何被創建出來的,
推薦閱讀:https://www.zhihu.com/question/23277575/answer/169698662
Spring的IOC理解
(1)IOC就是控制反轉,是指創建物件的控制權的轉移,以前創建物件的主動權和時機是由自己把控
的,而現在這種權力轉移到Spring容器中,并由容器根據組態檔去創建實體和管理各個實體之間的依
賴關系,物件與物件之間松散耦合,也利于功能的復用,DI依賴注入,和控制反轉是同一個概念的不同
角度的描述,即 應用程式在運行時依賴IoC容器來動態注入物件需要的外部資源,
(2)最直觀的表達就是,IOC讓物件的創建不用去new了,可以由spring自動生產,使用java的反射機
制,根據組態檔在運行時動態的去創建物件以及管理物件,并呼叫物件的方法的,
(3)Spring的IOC有三種注入方式 :構造器注入、setter方法注入、根據注解注入,
IoC讓相互協作的組件保持松散的耦合,而AOP編程允許你把遍布于應用各層的功能分離出來形成可重用的功能組件,
Spring IOC實作流程原理
在Spring中,最基本的IOC容器介面是BeanFactory - 這個介面為具體的IOC容器的實作作了最基本的功能規定,IOC 總體來說有兩處地方最重要,一個是創建 Bean 容器,一個是初始化 Bean.
啟動 Spring 容器
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext(“classpath:applicationfile.xml”);
}
ApplicationContext 啟動程序中,會負責創建實體 Bean,往各個 Bean 中注入依賴等.
spring ioc初始化流程?
resource定位 即尋找?戶定義的bean資源,由 ResourceLoader通過統?的接?Resource接?來完成beanDefinition載? BeanDefinitionReader讀取、決議Resource定位的資源 成BeanDefinition 載?到ioc中(通過HashMap進?維護BD) BeanDefinition注冊 即向IOC容器注冊這些BeanDefinition, 通過BeanDefinitionRegistery實作
BeanFactory,從名字上也很好理解,生產 bean 的工廠,它負責生產和管理各個 bean 實體,
流程:
啟動容器->創建bean工廠(BeanFactory)->依靠BeanFactory來getBean->創建bean->創建bean實體->通過反射生成bean->填充屬性,注入依賴->初始化bean
核心方法
@Override
public void refresh() throws BeansException, IllegalStateException {
// 來個鎖,不然 refresh() 還沒結束,你又來個啟動或銷毀容器的操作,那不就亂套了嘛
synchronized (this.startupShutdownMonitor) {
// 準備作業,記錄下容器的啟動時間、標記“已啟動”狀態、處理組態檔中的占位符
prepareRefresh();
// 這步比較關鍵,這步完成后,組態檔就會決議成一個個 Bean 定義,注冊到 BeanFactory 中,
// 當然,這里說的 Bean 還沒有初始化,只是配置資訊都提取出來了,
// 注冊也只是將這些資訊都保存到了注冊中心(說到底核心是一個 beanName-> beanDefinition 的 map)
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// 設定 BeanFactory 的類加載器,添加幾個 BeanPostProcessor,手動注冊幾個特殊的 bean
// 準備 Bean 容器: prepareBeanFactory,Spring 把我們在 xml 配置的 bean 都注冊以后,會"手動"注冊一些特殊的 bean,
prepareBeanFactory(beanFactory);
try {
// 【這里需要知道 BeanFactoryPostProcessor 這個知識點,Bean 如果實作了此介面,
// 那么在容器初始化以后,Spring 會負責呼叫里面的 postProcessBeanFactory 方法,】
// 這里是提供給子類的擴展點,到這里的時候,所有的 Bean 都加載、注冊完成了,但是都還沒有初始化
// 具體的子類可以在這步的時候添加一些特殊的 BeanFactoryPostProcessor 的實作類或做點什么事
postProcessBeanFactory(beanFactory);
// 呼叫 BeanFactoryPostProcessor 各個實作類的 postProcessBeanFactory(factory) 方法
invokeBeanFactoryPostProcessors(beanFactory);
// 注冊 BeanPostProcessor 的實作類,注意看和 BeanFactoryPostProcessor 的區別
// 此介面兩個方法: postProcessBeforeInitialization 和 postProcessAfterInitialization
// 兩個方法分別在 Bean 初始化之前和初始化之后得到執行,注意,到這里 Bean 還沒初始化
registerBeanPostProcessors(beanFactory);
// 初始化當前 ApplicationContext 的 MessageSource,國際化
initMessageSource();
// 初始化當前 ApplicationContext 的事件廣播器
initApplicationEventMulticaster();
// 從方法名就可以知道,典型的模板方法(鉤子方法),
// 具體的子類可以在這里初始化一些特殊的 Bean(在初始化 singleton beans 之前)
onRefresh();
// 注冊事件監聽器,監聽器需要實作 ApplicationListener 介面,
registerListeners();
// 重點,重點,重點
// 初始化所有的 singleton beans
//(lazy-init 的除外)
finishBeanFactoryInitialization(beanFactory);
// 最后,廣播事件,ApplicationContext 初始化完成
finishRefresh();
}
catch (BeansException ex) {
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - " +
"cancelling refresh attempt: " + ex);
}
// Destroy already created singletons to avoid dangling resources.
// 銷毀已經初始化的 singleton 的 Beans,以免有些 bean 會一直占用資源
destroyBeans();
// Reset 'active' flag.
cancelRefresh(ex);
// 把例外往外拋
throw ex;
}
finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}


spring的類加載
類從被加載到虛擬機記憶體中開始,直到卸載出記憶體為止,它的整個生命周期包括了:加載、驗證、準備、決議、初始化、使用和卸載這7個階段,其中,驗證、準備和決議這三個部分統稱為連接(linking),
當然Spring中的加載程序中,其加載程序還是遵循JVM的加載程序,
JVM的類加載

DI依賴注?流程? (實體化,處理Bean之間的依賴關系)
程序在Ioc初始化后,依賴注?的程序是?戶第?次向IoC容器索要Bean時觸發
- 如果設定lazy-init=true,會在第?次getBean的時候才初始化bean, lazy-init=false,會容器啟動的時候直接初始化(singleton bean);
- 調?BeanFactory.getBean()?成bean的;
- ?成bean程序運?裝飾器模式產?的bean都是beanWrapper(bean的增強);
依賴注?怎么處理bean之間的依賴關系?
其實就是通過在beanDefinition載?時,如果bean有依賴關系,通過占位符來代替,在調?getbean時候,如果遇到占位符,從ioc?獲取bean注?到本實體來
Spring的IOC注??式
一、構造器注入
將被依賴物件通過建構式的引數注入給依賴物件,并且在初始化物件的時候注入,
優點:
物件初始化完成后便可獲得可使用的物件,
缺點:
當需要注入的物件很多時,構造器引數串列將會很長;
不夠靈活,若有多種注入方式,每種方式只需注入指定幾個依賴,那么就需要提供多個多載的建構式,麻煩,
二、setter方法注入
IoC Service Provider通過呼叫成員變數提供的setter函式將被依賴物件注入給依賴類,
優點:
靈活,可以選擇性地注入需要的物件,
缺點:
依賴物件初始化完成后由于尚未注入被依賴物件,因此還不能使用,
三、介面注入
依賴類必須要實作指定的介面,然后實作該介面中的一個函式,該函式就是用于依賴注入,該函式的引數就是要注入的物件,
優點
介面注入中,介面的名字、函式的名字都不重要,只要保證函式的引數是要注入的物件型別即可,
缺點:
侵入性太強,不建議使用,
PS:什么是侵入性?
如果類A要使用別人提供的一個功能,若為了使用這功能,需要在自己的類中增加額外的代碼,這就是侵入性
Bean的?命周期?
- 實體化Bean: Ioc容器通過獲取BeanDefinition物件中的資訊進?實體化,實體化物件被包裝在BeanWrapper物件中
- 設定物件屬性(DI):通過BeanWrapper提供的設定屬性的接?完成屬性依賴注?;
- 注?Aware接?(BeanFactoryAware, 可以?這個?式來獲取其它 Bean,ApplicationContextAware):Spring會檢測該物件是否實作了xxxAware接?,并將相關的xxxAware實體注?給bean
- BeanPostProcessor:?定義的處理(分前置處理和后置處理)
- InitializingBean和init-method:執?我們??定義的初始化?法
- 使?
- destroy:bean的銷毀
IOC:控制反轉:將物件的創建權,由Spring管理. DI(依賴注?):在Spring創建物件的程序中,把物件依賴的屬性注?到類中,
Bean定義5種作?域
Spring容器中的bean可以分為5個范圍:
(1)singleton:默認,每個容器中只有一個bean的實體,單例的模式由BeanFactory自身來維護,
(2)prototype:為每一個bean請求提供一個實體,
(3)request:為每一個網路請求創建一個實體,在請求完成以后,bean會失效并被垃圾回收器回收,
(4)session:與request范圍類似,確保每個session中有一個bean的實體,在session過期后,bean會隨之失效,
(5)global-session:全域作用域,global-session和Portlet應用相關,當你的應用部署在Portlet容器中作業時,它包含很多portlet,如果你想要宣告讓所有的portlet共用全域的存盤變數的話,那么這全域變數需要存盤在global-session中,全域作用域與Servlet中的session作用域效果相同,
Spring 中的單例 bean 的執行緒安全問題了解嗎?
大部分時候我們并沒有在系統中使用多執行緒,所以很少有人會關注這個問題,單例 bean 存在執行緒問題,主要是因為當多個執行緒操作同一個物件的時候,對這個物件的非靜態成員變數的寫操作會存在執行緒安全問題,
常見的有兩種解決辦法:
-
在Bean物件中盡量避免定義可變的成員變數(不太現實),
-
在類中定義一個ThreadLocal成員變數,將需要的可變成員變數保存在 ThreadLocal 中(推薦的一種方式),
Spring如解決Bean回圈依賴問題?
回圈依賴說的是 A 依賴 B,而 B 又依賴 A,或者是 A 依賴 B,B 依賴 C,而 C 卻依賴 A,


Spring中回圈依賴場景有:構造器的回圈依賴 屬性的回圈依賴
答:Spring通過三級快取解決了回圈依賴,其中一級快取為單例池(singletonObjects),二級快取為早期曝光物件earlySingletonObjects,三級快取為早期曝光物件工廠(singletonFactories),
當A、B兩個類發生回圈參考時,在A完成實體化后,就使用實體化后的物件去創建一個物件工廠,并添加到三級快取中,如果A被AOP代理,那么通過這個工廠獲取到的就是A代理后的物件,如果A沒有被AOP代理,那么這個工廠獲取到的就是A實體化的物件,
當A進行屬性注入時,會去創建B,同時B又依賴了A,所以創建B的同時又會去呼叫getBean(a)來獲取需要的依賴,此時的getBean(a)會從快取中獲取:
第一步,先獲取到三級快取中的工廠;
第二步,呼叫物件工工廠的getObject方法來獲取到對應的物件,得到這個物件后將其注入到B中,緊接著B會走完它的生命周期流程,包括初始化、后置處理器等,
當B創建完后,會將B再注入到A中,此時A再完成它的整個生命周期,至此,回圈依賴結束!
面試官:”為什么要使用三級快取呢?二級快取能解決回圈依賴嗎?“
答:如果要使用二級快取解決回圈依賴,意味著所有Bean在實體化后就要完成AOP代理,這樣違背了Spring設計的原則,Spring在設計之初就是通過AnnotationAwareAspectJAutoProxyCreator這個后置處理器來在Bean生命周期的最后一步來完成AOP代理,而不是在實體化后就立馬進行AOP代理,
AOP(Aspect-Oriented Programming:面向切面編程)
AOP 是 OOP(面向物件編程)的一種延續補充,傳統的OOP開發中的代碼邏輯是自上而下的,在這程序中會產生些橫切面的問題,而這些橫切面問題又與主業務邏輯關系不大,散落在代碼中難以維護,
AOP就是把這些橫切面問題和主業務邏輯進行分離,達到解耦的?的,提?代碼重?性和開發效率;
AOP 解決了什么問題
通過上面的分析可以發現,AOP 主要用來解決:在不改變原有業務邏輯的情況下,增強橫切邏輯代碼,根本上解耦合,避免橫切邏輯代碼重復,
AOP 為什么叫面向切面編程
切 :指的是橫切邏輯,原有業務邏輯代碼不動,只能操作橫切邏輯代碼,所以面向橫切邏輯
面 :橫切邏輯代碼往往要影響的是很多個方法,每個方法如同一個點,多個點構成一個面,這里有一個面的概念
AOP 主要應?場景有:
- 記錄?志
- 監控性能
- 權限控制
- 事務管理
AOP 核?概念
1、切?(aspect):類是對物體特征的抽象,切?就是對橫切關注點的抽象
2、橫切關注點:對哪些?法進?攔截,攔截后怎么處理,這些關注點稱之為橫切關注點,
3、連接點(joinpoint):被攔截到的點,因為 Spring 只?持?法型別的連接點,所以在Spring 中連接點指的就是被攔截到的?法,實際上連接點還可以是欄位或者構造器,
4、切?點(pointcut):對連接點進?攔截的定義
5、通知(advice):所謂通知指的就是指攔截到連接點之后要執?的代碼,通知分為前置、后置、例外、最終、環繞通知五類,
6、?標物件:代理的?標物件
7、織?(weave):將切?應?到?標物件并導致代理物件創建的程序
8、引?(introduction):在不修改代碼的前提下,引?可以在運?期為類動態地添加?法或欄位,
AOP實作
AOP的實作方式基于IOC,通過beanPostProcessor來自定義bean的結構
主要分為兩大類:
一是采用動態代理技術,利用截取訊息的方式,對該訊息進行裝飾,以取代原有物件行為的執行;
二是采用靜態織入的方式,引入特定的語法創建“方面”,從而使得編譯器可以在編譯期間織入有關“方面”的代碼.
AOP實作的關鍵在于 代理模式,AOP代理主要分為靜態代理和動態代理,靜態代理的代表為AspectJ;動態代理則以Spring AOP為代表,
(1)AspectJ是靜態代理的增強,所謂靜態代理,就是AOP框架會在編譯階段生成AOP代理類,因此也稱為編譯時增強,他會在編譯階段將AspectJ(切面)織入到Java位元組碼中,運行的時候就是增強之后的AOP物件,因此也稱為編譯時增強;
(2)Spring AOP使用的動態代理,所謂的動態代理就是說AOP框架不會去修改位元組碼,而是每次運行時在記憶體中臨時為方法生成一個AOP物件,這個AOP物件包含了目標物件的全部方法,并且在特定的切點做了增強處理,并回呼原物件的方法,因此也被稱為運行時增強,
Spring AOP就是基于動態代理的,如果要代理的物件,實作了某個介面,那么Spring AOP會使用JDK Proxy,去創建代理物件,而對于沒有實作介面的物件,就無法使用 JDK Proxy 去進行代理了,這時候Spring AOP會使用Cglib ,這時候Spring AOP會使用 Cglib 生成一個被代理物件的子類來作為代理
①JDK動態代理只提供介面的代理,不支持類的代理,核心InvocationHandler介面和Proxy類, InvocationHandler 通過invoke()方法反射來呼叫目標類中的代碼,動態地將橫切邏輯和業務編織在一 起;接著,Proxy利用 InvocationHandler動態創建一個符合某一介面的的實體, 生成目標類的代理對 象,
②如果代理類沒有實作 InvocationHandler 介面,那么Spring AOP會選擇使用CGLIB來動態代理目 標類,CGLIB(Code Generation Library),是一個代碼生成的類別庫,可以在運行時動態的生成指定類 的一個子類物件,并覆寫其中特定方法并添加增強代碼,從而實作AOP,CGLIB是通過繼承的方式做的動態代 理,因此如果某個類被標記為final,那么它是無法使用CGLIB做動態代理的,
如下圖所示:
(3)靜態代理與動態代理區別在于生成AOP代理物件的時機不同,相對來說AspectJ的靜態代理方式具有更好的性能,但是AspectJ需要特定的編譯器進行處理,而Spring AOP則無需特定的編譯器處理,
jdk動態代理
- 通過bind?法建?代理與真實物件關系,通過Proxy.newProxyInstance(target)?成代理物件
- 代理物件通過反射invoke?法實作調?真實物件的?法
動態代理與靜態代理區別
- 靜態代理,程式運?前代理類的.class?件就存在了;
- 動態代理:在程式運?時利?反射動態創建代理物件<復?性,易?性,更加集中都調?invoke>
CGLIB與JDK動態代理區別
- Jdk必須提供接?才能使?;
- CGLIB不需要,只要?個?抽象類就能實作動態代理
Spring 中使?了哪些設計模式?
??模式: spring中的BeanFactory就是簡單??模式的體現,根據傳?唯?的標識來獲得bean物件;
單例模式: 提供了全域的訪問點BeanFactory;
代理模式: AOP功能的原理就使?代理模式(1、JDK動態代理,2、CGLib位元組碼?成技術代理,)
裝飾器模式: 依賴注?就需要使?BeanWrapper;
觀察者模式: spring中Observer模式常?的地?是listener的實作,如ApplicationListener,
策略模式: Bean的實體化的時候決定采?何種?式初始化bean實體(反射或者CGLIB動態位元組碼?成)
Spring設計模式推薦閱讀:https://snailclimb.gitee.io/javaguide/#/docs/system-design/framework/spring/Spring-Design-Patterns?id=%e6%8e%a7%e5%88%b6%e5%8f%8d%e8%bd%acioc%e5%92%8c%e4%be%9d%e8%b5%96%e6%b3%a8%e5%85%a5di
Spring 事務(基于AOP實作)
主流程介紹
眾所周知,Spring事務采用AOP的方式實作,我們從TransactionAspectSupport這個類開始分析,
- 獲取事務的屬性(@Transactional注解中的配置)
- 加載配置中的TransactionManager.
- 獲取收集事務資訊TransactionInfo
- 執行目標方法
- 出現例外,嘗試處理,
- 清理事務相關資訊
- 提交事務
//1. 獲取@Transactional注解的相關引數
TransactionAttributeSource tas = getTransactionAttributeSource();
// 2. 獲取事務管理器
final TransactionAttribute txAttr = (tas != null ? tas.getTransactionAttribute(method, targetClass) : null);
final PlatformTransactionManager tm = determineTransactionManager(txAttr);
final String joinpointIdentification = methodIdentification(method, targetClass, txAttr);
if (txAttr == null || !(tm instanceof CallbackPreferringPlatformTransactionManager)) {
// Standard transaction demarcation with getTransaction and commit/rollback calls.
// 3. 獲取TransactionInfo,包含了tm和TransactionStatus
TransactionInfo txInfo = createTransactionIfNecessary(tm, txAttr, joinpointIdentification);
Object retVal = null;
try {
// This is an around advice: Invoke the next interceptor in the chain.
// This will normally result in a target object being invoked.
// 4.執行目標方法
retVal = invocation.proceedWithInvocation();
}
catch (Throwable ex) {
//5.回滾
// target invocation exception
completeTransactionAfterThrowing(txInfo, ex);
throw ex;
}
finally {
// 6. 清理當前執行緒的事務相關資訊
cleanupTransactionInfo(txInfo);
}
// 提交事務
commitTransactionAfterReturning(txInfo);
return retVal;
}
關鍵物件介紹PlatformTransactionManager
TransactionManager是做什么的?它保存著當前的資料源連接,對外提供對該資料源的事務提交回滾操作介面,同時實作了事務相關操作的方法,一個資料源DataSource需要一個事務管理器,
屬性:DataSource
內部核心方法:
public commit 提交事務
public rollback 回滾事務
public getTransaction 獲得當前事務狀態
protected doSuspend 掛起事務
protected doBegin 開始事務,主要是執行了JDBC的con.setAutoCommit(false)方法,同時處理了很多和資料庫連接相關的ThreadLocal變數,
protected doCommit 提交事務
protected doRollback 回滾事務
protected doGetTransaction() 獲取事務資訊
final getTransaction 獲取事務狀態
@Nullable
protected PlatformTransactionManager determineTransactionManager(@Nullable TransactionAttribute txAttr) {
// Do not attempt to lookup tx manager if no tx attributes are set
if (txAttr == null || this.beanFactory == null) {
return getTransactionManager();
}
String qualifier = txAttr.getQualifier();
//如果指定了Bean則取指定的PlatformTransactionManager型別的Bean
if (StringUtils.hasText(qualifier)) {
return determineQualifiedTransactionManager(this.beanFactory, qualifier);
}
//如果指定了Bean的名稱,則根據bean名稱獲取對應的bean
else if (StringUtils.hasText(this.transactionManagerBeanName)) {
return determineQualifiedTransactionManager(this.beanFactory, this.transactionManagerBeanName);
}
else {
// 默認取一個PlatformTransactionManager型別的Bean
PlatformTransactionManager defaultTransactionManager = getTransactionManager();
if (defaultTransactionManager == null) {
defaultTransactionManager = this.transactionManagerCache.get(DEFAULT_TRANSACTION_MANAGER_KEY);
if (defaultTransactionManager == null) {
defaultTransactionManager = this.beanFactory.getBean(PlatformTransactionManager.class);
this.transactionManagerCache.putIfAbsent(
DEFAULT_TRANSACTION_MANAGER_KEY, defaultTransactionManager);
}
}
return defaultTransactionManager;
}
}
Spring 管理事務的方式有幾種?
編程式事務,在代碼中硬編碼,(不推薦使用)
宣告式事務,在組態檔中配置(推薦使用)
宣告式事務又分為兩種:
- 基于XML的宣告式事務
- 基于注解的宣告式事務
Spring 事務中的隔離級別有哪幾種?
TransactionDefinition 介面中定義了五個表示隔離級別的常量:
?TransactionDefinition.ISOLATION_DEFAULT: 使用后端資料庫默認的隔離級別,Mysql 默認采用的 REPEATABLE_READ隔離級別 Oracle 默認采用的 READ_COMMITTED隔離級別.
?TransactionDefinition.ISOLATION_READ_UNCOMMITTED: 最低的隔離級別,允許讀取尚未提交的資料變更,可能會導致臟讀、幻讀或不可重復讀
?TransactionDefinition.ISOLATION_READ_COMMITTED: 允許讀取并發事務已經提交的資料,可以阻止臟讀,但是幻讀或不可重復讀仍有可能發生
?TransactionDefinition.ISOLATION_REPEATABLE_READ: 對同一欄位的多次讀取結果都是一致的,除非資料是被本身事務自己所修改,可以阻止臟讀和不可重復讀,但幻讀仍有可能發生,
?TransactionDefinition.ISOLATION_SERIALIZABLE: 最高的隔離級別,完全服從ACID的隔離級別,所有的事務依次逐個執行,這樣事務之間就完全不可能產生干擾,也就是說,該級別可以防止臟讀、不可重復讀以及幻讀,但是這將嚴重影響程式的性能,通常情況下也不會用到該級別,
Spring 事務中哪幾種事務傳播行為?
支持當前事務的情況:
?TransactionDefinition.PROPAGATION_REQUIRED: 如果當前存在事務,則加入該事務;如果當前沒有事務,則創建一個新的事務,
?TransactionDefinition.PROPAGATION_SUPPORTS: 如果當前存在事務,則加入該事務;如果當前沒有事務,則以非事務的方式繼續運行,
?TransactionDefinition.PROPAGATION_MANDATORY: 如果當前存在事務,則加入該事務;如果當前沒有事務,則拋出例外,(mandatory:強制性)
不支持當前事務的情況:
?TransactionDefinition.PROPAGATION_REQUIRES_NEW: 創建一個新的事務,如果當前存在事務,則把當前事務掛起,
?TransactionDefinition.PROPAGATION_NOT_SUPPORTED: 以非事務方式運行,如果當前存在事務,則把當前事務掛起,
?TransactionDefinition.PROPAGATION_NEVER: 以非事務方式運行,如果當前存在事務,則拋出例外,
其他情況:
?TransactionDefinition.PROPAGATION_NESTED: 如果當前存在事務,則創建一個事務作為當前事務的嵌套事務來運行;如果當前沒有事務,則該取值等價于TransactionDefinition.PROPAGATION_REQUIRED,
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/3246.html
標籤:其他
