javascript
Spring的AOP和IOC是什么?使用场景有哪些?Spring事务与数据库事务,传播行为,数据库隔离级别
Spring的AOP和IOC是什么?使用場景有哪些?Spring事務(wù)與數(shù)據(jù)庫事務(wù),傳播行為,數(shù)據(jù)庫隔離級別
AOP:面向切面編程。
即在一個功能模塊中新增其他功能,比方說你要下樓取個快遞,你同事對你說幫我也取一下唄,你就順道取了。在工作中如果系統(tǒng)中有些包和類中沒有使用AOP,例如日志,事務(wù)和異常處理,那么就必須在每個類和方法中去實現(xiàn)它們。 代碼糾纏每個類和方法中都包含日志,事務(wù)以及異常處理甚至是業(yè)務(wù)邏輯。在一個這樣的方法中,很難分清代碼中實際做的是什么處理。AOP 所做的就是將所有散落各處的事務(wù)代碼集中到一個事務(wù)切面中。
場景
比方說我現(xiàn)在要弄一個日志,記錄某些個接口調(diào)用的方法時間。使用Aop我可以在這個接口前插入一段代碼去記錄開始時間,在這個接口后面去插入一段代碼記錄結(jié)束時間。
又或者你去訪問數(shù)據(jù)庫,而你不想管事務(wù)(太煩),所以,Spring在你訪問數(shù)據(jù)庫之前,自動幫你開啟事務(wù),當(dāng)你訪問數(shù)據(jù)庫結(jié)束之后,自動幫你提交/回滾事務(wù)!
異常處理你可以開啟環(huán)繞通知,一旦運行接口報錯,環(huán)繞通知捕獲異常跳轉(zhuǎn)異常處理頁面。
動態(tài)代理
Spring AOP使用的動態(tài)代理,所謂的動態(tài)代理就是說AOP框架不會去修改字節(jié)碼,而是在內(nèi)存中臨時為方法生成一個AOP對象,這個AOP對象包含了目標(biāo)對象的全部方法,并且在特定的切點做了增強(qiáng)處理,并回調(diào)原對象的方法。它的動態(tài)代理主要有兩種方式,JDK動態(tài)代理和CGLIB動態(tài)代理。JDK動態(tài)代理通過反射來接收被代理的類,并且要求被代理的類必須實現(xiàn)一個接口。JDK動態(tài)代理的核心是InvocationHandler接口和Proxy類。如果目標(biāo)類沒有實現(xiàn)接口,那么Spring AOP會選擇使用CGLIB來動態(tài)代理目標(biāo)類。CGLIB是一個代碼生成的類庫,可以在運行時動態(tài)的生成某個類的子類,注意,CGLIB是通過繼承的方式做的動態(tài)代理,因此如果某個類被標(biāo)記為final,那么它是無法使用CGLIB做動態(tài)代理的。
IOC:依賴注入或者叫做控制反轉(zhuǎn)。
正常情況下我們使用一個對象時都是需要new Object()的。而ioc是把需要使用的對象提前創(chuàng)建好,放到spring的容器里面。
所有需要使用的類都會在spring容器中登記,告訴spring你是個什么東西,你需要什么東西,然后spring會在系統(tǒng)運行到適當(dāng)?shù)臅r候,把你要的東西主動給你,同時也把你交給其他需要你的東西。所有的類的創(chuàng)建、銷毀都由 spring來控制,也就是說控制對象生存周期的不再是引用它的對象,而是spring。DI(依賴注入)其實就是IOC的另外一種說法,其實它們是同一個概念的不同角度描述。
場景:
正常情況下我們使用一個對象時都是需要new Object() 的。而ioc是把需要使用的對象提前創(chuàng)建好,放到spring的容器里面。需要使用的時候直接使用就行,而且可以設(shè)置單例或多例,非常靈活。
我們在service層想調(diào)用另外一個service的方法,不需要去new了,直接把它交給spring管理,然后用注解的方式引入就能使用。
IOC三種注入方式
(1)XML:Bean實現(xiàn)類來自第三方類庫,例如DataSource等。需要命名空間等配置,例如:context,aop,mvc。
(2)注解:在開發(fā)的類使用@Controller,@Service等注解
(3)Java配置類:通過代碼控制對象創(chuàng)建邏輯的場景。例如:自定義修改依賴類庫。
什么是事務(wù)?
事務(wù)是訪問并可能更新數(shù)據(jù)庫中各種數(shù)據(jù)項的一個程序執(zhí)行單元。
Spring事務(wù)與數(shù)據(jù)庫事務(wù)關(guān)系?
Spring的事務(wù)是對數(shù)據(jù)庫的事務(wù)的封裝,最后本質(zhì)的實現(xiàn)還是在數(shù)據(jù)庫,假如數(shù)據(jù)庫不支持事務(wù)的話,Spring的事務(wù)是沒有作用的。所以說Spring事務(wù)的底層依賴MySQL的事務(wù),Spring是在代碼層面利用AOP實現(xiàn),執(zhí)行事務(wù)的時候使用TransactionInceptor進(jìn)行攔截,然后處理。本質(zhì)是對方法前后進(jìn)行攔截,然后在目標(biāo)方法開始之前創(chuàng)建或者加入一個事務(wù),執(zhí)行完目標(biāo)方法之后根據(jù)執(zhí)行的情況提交或者回滾。
屬性(特性)
A(原子性):要么全部完成,要么完全不起作用
C(一致性):一旦事務(wù)完成(不管成功還是失敗),業(yè)務(wù)處于一致的狀態(tài),而不會是部分完成,部分失敗。
I(隔離性):多事務(wù)會同時處理相同的數(shù)據(jù),因此每個事務(wù)都應(yīng)該與其他事務(wù)隔離開來,防止數(shù)據(jù)損壞。
D(持久性):一旦事務(wù)完成,無論發(fā)生什么系統(tǒng)錯誤,它的結(jié)果都不應(yīng)該受到影響,事務(wù)的結(jié)果被寫到持久化存儲器中。
什么叫事務(wù)傳播行為?
傳播,至少有兩個東西,才可以發(fā)生傳播。單體不存在傳播這個行為。事務(wù)傳播行為就是當(dāng)一個事務(wù)方法被另一個事務(wù)方法調(diào)用時,這個事務(wù)方法應(yīng)該如何進(jìn)行。
Spring支持7中事務(wù)傳播行為
propagation_required(需要傳播):當(dāng)前沒有事務(wù)則新建事務(wù),有則加入當(dāng)前事務(wù)
propagation_supports(支持傳播):支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù)則以非事務(wù)方式執(zhí)行
propagation_mandatory(強(qiáng)制傳播):使用當(dāng)前事務(wù),如果沒有則拋出異常
propagation_nested(嵌套傳播):如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行,如果當(dāng)前沒有事務(wù),則執(zhí)行需要傳播行為。
propagation_never(絕不傳播):以非事務(wù)的方式執(zhí)行,如果當(dāng)前有事務(wù)則拋出異常
propagation_requires_new(傳播需要新的):新建事務(wù),如果當(dāng)前有事務(wù)則把當(dāng)前事務(wù)掛起
propagation_not_supported(不支持傳播):以非事務(wù)的方式執(zhí)行,如果當(dāng)前有事務(wù)則把當(dāng)前事務(wù)掛起
數(shù)據(jù)庫事務(wù)的隔離級別
數(shù)據(jù)庫事務(wù)的隔離級別有4個,由低到高依次為Read uncommitted、Read committed、Repeatable read、Serializable,這四個級別可以逐個解決臟讀、不可重復(fù)讀、幻讀這幾類問題。
√: 可能出現(xiàn) ×: 不會出現(xiàn)
注意:我們討論隔離級別的場景,主要是在多個事務(wù)并發(fā)的情況下,因此,接下來的講解都圍繞事務(wù)并發(fā)。
Read uncommitted 讀未提交
公司發(fā)工資了,領(lǐng)導(dǎo)把20000元打到廖志偉的賬號上,但是該事務(wù)并未提交,而廖志偉正好去查看賬戶,發(fā)現(xiàn)工資已經(jīng)到賬,是20000元整,非常高興。可是不幸的是,領(lǐng)導(dǎo)發(fā)現(xiàn)發(fā)給廖志偉的工資金額不對,是16000元,于是迅速回滾了事務(wù),修改金額后,將事務(wù)提交,最后廖志偉實際的工資只有16000元,廖志偉空歡喜一場。
出現(xiàn)上述情況,即我們所說的臟讀,兩個并發(fā)的事務(wù),“事務(wù)A:領(lǐng)導(dǎo)給廖志偉發(fā)工資”、“事務(wù)B:廖志偉查詢工資賬戶”,事務(wù)B讀取了事務(wù)A尚未提交的數(shù)據(jù)。當(dāng)隔離級別設(shè)置為Read uncommitted時,就可能出現(xiàn)臟讀,如何避免臟讀,請看下一個隔離級別。
Read committed 讀提交
廖志偉拿著工資卡去消費,系統(tǒng)讀取到卡里確實有2000元,而此時她的老婆也正好在網(wǎng)上轉(zhuǎn)賬,把廖志偉工資卡的2000元轉(zhuǎn)到另一賬戶,并在廖志偉之前提交了事務(wù),當(dāng)廖志偉扣款時,系統(tǒng)檢查到廖志偉的工資卡已經(jīng)沒有錢,扣款失敗,廖志偉十分納悶,明明卡里有錢,為何…
出現(xiàn)上述情況,即我們所說的不可重復(fù)讀,兩個并發(fā)的事務(wù),“事務(wù)A:廖志偉消費”、“事務(wù)B:廖志偉的老婆網(wǎng)上轉(zhuǎn)賬”,事務(wù)A事先讀取了數(shù)據(jù),事務(wù)B緊接了更新了數(shù)據(jù),并提交了事務(wù),而事務(wù)A再次讀取該數(shù)據(jù)時,數(shù)據(jù)已經(jīng)發(fā)生了改變。當(dāng)隔離級別設(shè)置為Read committed時,避免了臟讀,但是可能會造成不可重復(fù)讀。大多數(shù)數(shù)據(jù)庫的默認(rèn)級別就是Read committed,比如Sql Server , Oracle。如何解決不可重復(fù)讀這一問題,請看下一個隔離級別。
Repeatable read 重復(fù)讀
當(dāng)廖志偉拿著工資卡去消費時,一旦系統(tǒng)開始讀取工資卡信息(即事務(wù)開始),廖志偉的老婆就不可能對該記錄進(jìn)行修改,也就是廖志偉的老婆不能在此時轉(zhuǎn)賬。這就避免了不可重復(fù)讀。廖志偉的老婆工作在銀行部門,她時常通過銀行內(nèi)部系統(tǒng)查看廖志偉的信用卡消費記錄。有一天,她正在查詢到廖志偉當(dāng)月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)為80元,而廖志偉此時正好在外面胡吃海喝后在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction … ),并提交了事務(wù),隨后廖志偉的老婆將廖志偉當(dāng)月信用卡消費的明細(xì)打印到A4紙上,卻發(fā)現(xiàn)消費總額為1080元,廖志偉的老婆很詫異,以為出現(xiàn)了幻覺,幻讀就這樣產(chǎn)生了。當(dāng)隔離級別設(shè)置為Repeatable read時,可以避免不可重復(fù)讀,但會出現(xiàn)幻讀。注:MySQL的默認(rèn)隔離級別就是Repeatable read。
Serializable 序列化
Serializable是最高的事務(wù)隔離級別,同時代價也花費最高,性能很低,一般很少使用,在該級別下,事務(wù)順序執(zhí)行,不僅可以避免臟讀、不可重復(fù)讀,還避免了幻像讀。
總結(jié)
以上是生活随笔為你收集整理的Spring的AOP和IOC是什么?使用场景有哪些?Spring事务与数据库事务,传播行为,数据库隔离级别的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HashMap底层实现原理,红黑树,B+
- 下一篇: Redis支持的数据类型以及使用场景,持