繼續(xù)卷!面試又問Spring 事務有幾種傳播行為和隔離級別?
面試又被問到了事務,來吧,要么卷起來,要么躺平。卷不動躺平會不會導致數(shù)據(jù)不一致?
事務概念
事務是數(shù)據(jù)庫管理系統(tǒng)執(zhí)行過程中的一個邏輯單位,由一個有限的數(shù)據(jù)庫操作序列構(gòu)成。
說簡單點就是,要么所有執(zhí)行success,不然就fail。它最終的目標:數(shù)據(jù)不會被破壞。即事務操作成功,數(shù)據(jù)的結(jié)果和業(yè)務期待的結(jié)果是一致的。
事務的屬性
一個邏輯工作單元要成為事務,必須滿足所謂的ACID(原子性、一致性、隔離性和持久性)屬性
- 原子性(Atomicity)
- 一致性(Consistency)
- 隔離性(Isolation)
- 持久性(Durability)
1:原子性(Atomicity):原子性要求事務作為一個不可分割的整體被執(zhí)行,包含在其中的對數(shù)據(jù)庫的操作要么全部被執(zhí)行,要么都不執(zhí)行(其中有一個操作失敗,就全部失敗)。
2:一致性(Consistency):一致性要求事務應確保數(shù)據(jù)庫的狀態(tài)從一個一致狀態(tài)轉(zhuǎn)變?yōu)榱硪粋€一致狀態(tài)。一致狀態(tài)的含義是數(shù)據(jù)庫中的數(shù)據(jù)應滿足完整性約束。
執(zhí)行前數(shù)據(jù)間的一致性狀態(tài) === 執(zhí)行后數(shù)據(jù)間的一致性狀態(tài)
3:隔離性(Isolation):事務的隔離性要求多個事務并發(fā)執(zhí)行時,一個事務的執(zhí)行不應影響其他事務的執(zhí)行。
4:持久性(Durability):事務的持久性是一旦整個事務提交成功,數(shù)據(jù)的修改應該永久保存在數(shù)據(jù)庫中,并不可逆轉(zhuǎn)。
隔離性(Isolation)
事務指定了4種隔離級別(從弱到強分別是):
- Read Uncommitted
- Read Committed
- Repeatable Read
- Serializable
在事務的并發(fā)操作中可能會出現(xiàn)臟讀(dirty read),不可重復讀(repeatable read),幻讀(phantom read)。
1:Read Uncommitted(讀未提交):一個事務可以讀取另一個未提交事務的數(shù)據(jù)。
2:Read Committed(讀提交):一個事務要等另一個事務提交后才能讀取數(shù)據(jù)。
3:Repeatable Read(重復讀):在開始讀取數(shù)據(jù)(事務開啟)時,不再允許修改操作。
4:Serializable(序列化):Serializable 是最高的事務隔離級別,在該級別下,事務串行化順序執(zhí)行,可以避免臟讀、不可重復讀與幻讀。
大多數(shù)數(shù)據(jù)庫默認的事務隔離級別是Read committed,比如Sql Server , Oracle。MySQL的默認隔離級別是Repeatable read。
Spring事務的傳播性
事務的傳播級別和數(shù)據(jù)隔離級別,是事務控制的兩個主要特性。傳播級別定義的是事務的控制范圍,事務隔離級別定義的是事務在數(shù)據(jù)庫讀寫方面的控制范圍。
Spring事務傳播性有七種,REQUIRED、SUPPORTS、REQUIRES-NEW、NOT-SUPPORTED、MANDATORY、NEVER、NESTED。如下思維導圖:
Spring事務的傳播特性介紹:
- PROPAGATION_REQUIRED: 如果存在一個事務,則支持當前事務。如果沒有事務則開啟新的事物。
- PROPAGATION_SUPPORTS: 如果存在一個事務,支持當前事務。如果沒有事務,則非事務的執(zhí)行。
- PROPAGATION_MANDATORY: 如果已經(jīng)存在一個事務,支持當前事務。如果沒有一個活動的事務,則拋出異常。
- PROPAGATION_REQUIRES_NEW: 總是開啟一個新的事務。如果一個事務已經(jīng)存在,則將這個存在的事務掛起。
- PROPAGATION_NOT_SUPPORTED: 總是非事務地執(zhí)行,并掛起任何存在的事務。
- PROPAGATION_NEVER: 總是非事務地執(zhí)行,如果存在一個活動事務,則拋出異常
- 7.(spring)PROPAGATION_NESTED:如果一個活動的事務存在,則運行在一個嵌套的事務中. 如果沒有活動事務, 則按TransactionDefinition.PROPAGATION_REQUIRED 屬性執(zhí)行。
Spring事務傳播特性總結(jié):
- 1.只要定義為spring的bean就可以對里面的方法使用@Transactional注解。
- 2.Spring的事務傳播是Spring特有的。不是對底層jdbc的代理。
- 3.使用spring聲明式事務,spring使用AOP來支持聲明式事務,會根據(jù)事務屬性,自動在[方法調(diào)用之前決定是否開啟一個事務],并在[方法執(zhí)行之后]決定事務提交或回滾事務。
- 4.Spring支持的PROPAGATION_NESTED 與PROPAGATION_REQUIRES_NEW的區(qū)別: PROPAGATION_REQUIRES_NEW:二個事務沒有信賴關(guān)系,不會存在A事務的成功取決于B事務的情況。有可能存在A提交B失敗。A失敗(比如執(zhí)行到doSomeThingB的時候拋出異常)B提交,AB都提交,AB都失敗的可能。PROPAGATION_NESTED:與PROPAGATION_REQUIRES_NEW不同的是,內(nèi)嵌事務B會信賴A。即存在A失敗B失敗。A成功,B失敗。A成功,B成功。而不存在A失敗,B成功。
- 5.特別注意PROPAGATION_NESTED的使用條件:使用JDBC 3.0驅(qū)動時,僅僅支持DataSourceTransactionManager作為事務管理器。需要JDBC 驅(qū)動的java.sql.Savepoint類。有一些JTA的事務管理器實現(xiàn)可能也提供了同樣的功能。使用PROPAGATION_NESTED,還需 要把PlatformTransactionManager的nestedTransactionAllowed屬性設為true;而 nestedTransactionAllowed屬性值默認為false;
- 6.特別注意PROPAGATION_REQUIRES_NEW的使用條件:JtaTransactionManager作為事務管理器
Spring事務的隔離級別?
Spring事務的隔離級別:
- ISOLATION_DEFAULT:這是一個PlatfromTransactionManager默認的隔離級別,使用數(shù)據(jù)庫默認的事務隔離級別。
- ISOLATION_READ_UNCOMMITTED:這是事務最低的隔離級別,它充許令外一個事務可以看到這個事務未提交的數(shù)據(jù)。
- ISOLATION_READ_COMMITTED:保證一個事務修改的數(shù)據(jù)提交后才能被另外一個事務讀取。另外一個事務不能讀取該事務未提交的數(shù)據(jù)。
- ISOLATION_REPEATABLE_READ:這種事務隔離級別可以防止臟讀,不可重復讀。但是可能出現(xiàn)幻像讀。它除了保證一個事務不能讀取另一個事務未提交的數(shù)據(jù)外,還保證了避免下面的情況產(chǎn)生(不可重復讀)。
- ISOLATION_SERIALIZABLE 這是花費最高代價但是最可靠的事務隔離級別。事務被處理為順序執(zhí)行。除了防止臟讀,不可重復讀外,還避免了幻像讀。除了第一個是spring特有的,另外四個與JDBC的隔離級別相對應。第二種隔離級別會產(chǎn)生臟讀,不可重復讀和幻像讀,特別是臟讀,一般情況下 是不允許的,所以這種隔離級別是很少用到的。大多說數(shù)據(jù)庫的默認格里基本是第三種。它能消除臟讀,但是可重復讀保證不了。第四種隔離級別也有一些數(shù)據(jù)庫作 為默認的隔離級別,比如MySQL。最后一種用的地方不多,除非是多數(shù)據(jù)訪問的要求特別高,否則輕易不要用它,因為它會嚴重影響數(shù)據(jù)庫的性能
Spring事務的架構(gòu)?
Spring 的事務框架設計理念的基本原則是:讓事務管理的關(guān)注點與數(shù)據(jù)訪問關(guān)注點相分離。
架構(gòu)
Spring 的事務抽象包括3個主要接口,分別是PlatformTransactionManager、TransactionDefinition、TransactionSatus。
- PlatformTransactionManager負責界定事務邊界;TransactionDefinition負責定義事務的相關(guān)屬性,包括隔離級別、傳播行為等;PlatformTransactionManager參照TransactionDefinition的屬性定義來開啟相關(guān)事務。事務開啟之后到事務結(jié)束期間的事務狀態(tài)由TransactionStatus負責,我們可以通過TransactionStatus對事務進行有限的控制。
- TransactionDefinition常用的實現(xiàn)有DefaultTransactionDefinition和TransactionTemplate(這兩個主要用于編程式的事務場景)、DefaultTransactionAttribute和RuleBasedTransactionAttribute(這兩個主要使用Spring AOP 進行聲明式事務管理的場景中,RuleBasedTransactionAttribute允許我們同時制定多個回滾規(guī)則)。
- TransactionStatus有一個實現(xiàn)類DefaultTransactionStatus用來記錄事務的狀態(tài)信息。PlatformTransactionManager的實現(xiàn)類可以分為面向局部事務和面向全局事務兩個分支。常用的面向局部事務的PlatformTransactionManager有DataSourceTransactionManager(用于JDBC和Mybatis)和HibernateTransactionManager。
使用Spring如何進行事務管理?
事務管理配置
- 編程式事務
- 聲明式事務
編程式事務使用TransactionTemplate或者直接使用底層的PlatformTransactionManager。對于編程式事務管理,spring推薦使用TransactionTemplate。
聲明式事務是建立在AOP之上的。其本質(zhì)是對方法前后進行攔截,然后在目標方法開始之前創(chuàng)建或者加入一個事務,在執(zhí)行完目標方法之后根據(jù)執(zhí)行情況提交或者回滾事務。聲明式事務最大的優(yōu)點就是不需要通過編程的方式管理事務,這樣就不需要在業(yè)務邏輯代碼中摻雜事務管理的代碼,只需在配置文件中做相關(guān)的事務規(guī)則聲明(或通過基于@Transactional注解的方式),便可以將事務規(guī)則應用到業(yè)務邏輯中。
顯然聲明式事務管理要優(yōu)于編程式事務管理,這正是spring倡導的非侵入式的開發(fā)方式。聲明式事務管理使業(yè)務代碼不受污染,一個普通的POJO對象,只要加上注解就可以獲得完全的事務支持。和編程式事務相比,聲明式事務唯一不足地方是,它的最細粒度只能作用到方法級別,無法做到像編程式事務那樣可以作用到代碼塊級別。但是即便有這樣的需求,也存在很多變通的方法,比如,可以將需要進行事務管理的代碼塊獨立為方法等等。
聲明式事務管理也有兩種常用的方式,一種是基于tx和aop名字空間的xml配置文件,另一種就是基于@Transactional注解。顯然基于注解的方式更簡單易用,更清爽。
本文轉(zhuǎn)載自微信公眾號「Java編程技術(shù)樂園」,可以通過以下二維碼關(guān)注。轉(zhuǎn)載本文請聯(lián)系Java編程技術(shù)樂園公眾號。