@Transactional注解支持9個屬性的設(shè)置播瞳,這里只講解其中使用較多的三個屬性:readOnly掸刊、propagation、isolation赢乓。其中propagation屬性用來枚舉事務(wù)的傳播行為忧侧,isolation用來設(shè)置事務(wù)隔離級別,readOnly進行讀寫事務(wù)控制牌芋。
一蚓炬、readOnly讀寫事務(wù)控制
readOnly=true表明所注解的方法或類只是讀取數(shù)據(jù)。readOnly=false表明所注解的方法或類是增加躺屁,刪除肯夏,修改數(shù)據(jù)。
二、isolation事務(wù)隔離級別
我們在使用事務(wù)過程中驯击,通常會發(fā)生以下三種情況:
1烁兰、臟讀(dirty read):當一個事務(wù)讀取另一個事務(wù)尚未提交的修改時,產(chǎn)生臟讀徊都。
2沪斟、不可重復(fù)讀(non-repeatable
read):同一查詢在同一事務(wù)中多次進行,由于其他提交事務(wù)所做的修改或刪除暇矫,每次返回不同的結(jié)果集主之,此時發(fā)生非重復(fù)讀。
3李根、幻像讀(phantom
read):同一查詢在同一事務(wù)中多次進行槽奕,由于其他提交事務(wù)所做的插入操作,每次返回不同的結(jié)果集朱巨,此時發(fā)生幻像讀史翘。
針對上述三種情況枉长,Spring提供了5種事務(wù)隔離級別予以解決:
1冀续、DEFAULT默認級別
DEFAULT為數(shù)據(jù)源(數(shù)據(jù)庫)的默認隔離級別,以目前常用的MySQL為例必峰,默認的隔離級別通常為REPEATABLE_READ洪唐。
2、READ_UNCOMMITTED未授權(quán)讀取級別
這是最低的隔離級別吼蚁,一個事務(wù)能讀取到別的事務(wù)未提交的更新數(shù)據(jù)凭需,很不安全,可能出現(xiàn)丟失更新肝匆、臟讀粒蜈、不可重復(fù)讀、幻讀旗国。
3枯怖、READ_COMMITTED授權(quán)讀取級別
以操作同一行數(shù)據(jù)為前提,讀事務(wù)允許其他讀事務(wù)和寫事務(wù)能曾,未提交的寫事務(wù)禁止其他讀事務(wù)和寫事務(wù)度硝。此隔離級別可以防止更新丟失、臟讀寿冕,但不能防止不可重復(fù)讀蕊程、幻讀。此隔離級別可以通過“瞬間共享讀鎖”和“排他寫鎖”實現(xiàn)驼唱。
4藻茂、REPEATABLE_READ可重復(fù)讀取級別
保證同一事務(wù)中先后執(zhí)行的多次查詢將返回同一結(jié)果,不受其他事務(wù)影響。以操作同一行數(shù)據(jù)為前提辨赐,讀事務(wù)禁止其他寫事務(wù)岗钩,但允許其他讀事務(wù),未提交的寫事務(wù)禁止其他讀事務(wù)和寫事務(wù)肖油。此隔離級別可以防止更新丟失兼吓、臟讀、不可重復(fù)讀森枪,但不能防止幻讀视搏。?
5、SERIALIZABLE序列化級別
所有的事務(wù)依次逐個執(zhí)行县袱,這樣事務(wù)之間就完全不可能產(chǎn)生干擾浑娜。提供嚴格的事務(wù)隔離,此隔離級別可以防止更新丟失式散、臟讀筋遭、不可重復(fù)讀、幻讀暴拄。如果僅僅通過“行級鎖”是無法實現(xiàn)事務(wù)序列化的漓滔,必須通過其他機制保證新插入的數(shù)據(jù)不會被剛執(zhí)行查詢操作的事務(wù)訪問到。
隔離級別越高乖篷,越能保證數(shù)據(jù)的完整性和一致性响驴,但是對并發(fā)性能的影響也越大。對于多數(shù)應(yīng)用程序撕蔼,可以優(yōu)先考慮把數(shù)據(jù)庫系統(tǒng)的隔離級別設(shè)為Read Committed豁鲤。它能夠避免更新丟失、臟讀鲸沮,而且具有較好的并發(fā)性能琳骡。盡管它會導(dǎo)致不可重復(fù)讀、幻讀這些并發(fā)問題讼溺,在可能出現(xiàn)這類問題的個別場合楣号,可以由應(yīng)用程序采用悲觀鎖或樂觀鎖來控制。
三肾胯、Propagation事務(wù)傳播行為
Propagation屬性用來枚舉事務(wù)的傳播行為竖席。所謂事務(wù)傳播行為就是多個事務(wù)方法相互調(diào)用時,事務(wù)如何在這些方法間傳播敬肚。Spring支持7種事務(wù)傳播行為毕荐,默認為REQUIRED。
1艳馒、REQUIRED
REQUIRED是常用的事務(wù)傳播行為憎亚,如果當前沒有事務(wù)员寇,就新建一個事務(wù),如果已經(jīng)存在一個事務(wù)中第美,加入到這個事務(wù)中蝶锋。
2、SUPPORTS
SUPPORTS表示當前方法不需要事務(wù)上下文什往,但是如果存在當前事務(wù)的話扳缕,那么這個方法會在這個事務(wù)中運行。
3别威、MANDATORY
MANDATORY表示該方法必須在事務(wù)中運行躯舔,如果當前事務(wù)不存在,則會拋出一個異常省古。不會主動開啟一個事務(wù)粥庄。
4、REQUIRES_NEW
REQUIRES_NEW表示當前方法必須運行在它自己的事務(wù)中豺妓。一個新的事務(wù)將被啟動惜互,如果存在當前事務(wù),在該方法執(zhí)行期間琳拭,當前事務(wù)會被掛起(如果一個事務(wù)已經(jīng)存在训堆,則先將這個存在的事務(wù)掛起)。如果使用JTATransactionManager的話臀栈,則需要訪問TransactionManager蔫慧。
5、NOT_SUPPORTED
NOT_SUPPORTED表示該方法不應(yīng)該運行在事務(wù)中权薯,如果存在當前事務(wù),在該方法運行期間睡扬,當前事務(wù)將被掛起盟蚣。如果使用JTATransactionManager的話,則需要訪問TransactionManager卖怜。
6屎开、NEVER
NEVER表示當前方法不應(yīng)該運行在事務(wù)上下文中,如果當前正有一個事務(wù)在運行马靠,則會拋出異常奄抽。
7、NESTED
NESTED表示如果當前已經(jīng)存在一個事務(wù)甩鳄,那么該方法將會在嵌套事務(wù)中運行逞度。嵌套的事務(wù)可以獨立于當前事務(wù)進行單獨地提交或回滾。如果當前事務(wù)不存在妙啃,那么其行為與REQUIRED一樣档泽。嵌套事務(wù)一個非常重要的概念就是內(nèi)層事務(wù)依賴于外層事務(wù)俊戳。外層事務(wù)失敗時,會回滾內(nèi)層事務(wù)所做的動作馆匿。而內(nèi)層事務(wù)操作失敗并不會引起外層事務(wù)的回滾抑胎。
綜上所述,NESTED和REQUIRES_NEW非常相似渐北,都是開啟一個屬于它自己的新事務(wù)阿逃。使用REQUIRES_NEW時,內(nèi)層事務(wù)與外層事務(wù)就像兩個獨立的事務(wù)一樣赃蛛,一旦內(nèi)層事務(wù)進行了提交后盆昙,外層事務(wù)不能對其進行回滾。當內(nèi)部事務(wù)開始執(zhí)行時, 外部事務(wù)將被掛起, 內(nèi)務(wù)事務(wù)結(jié)束時,外部事務(wù)將繼續(xù)執(zhí)行焊虏。兩個事務(wù)互不影響淡喜,兩個事務(wù)不是一個真正的嵌套事務(wù),同時它還需要JTA事務(wù)管理器的支持诵闭。
使用NESTED時炼团,外層事務(wù)的回滾可以引起內(nèi)層事務(wù)的回滾。而內(nèi)層事務(wù)的異常并不會導(dǎo)致外層事務(wù)的回滾疏尿,它是一個真正的嵌套事務(wù)瘟芝。嵌套事務(wù)開始執(zhí)行時, 它將取得一個 savepoint,如果這個嵌套事務(wù)失敗, 將回滾到此savepoint褥琐。潛套事務(wù)是外部事務(wù)的一部分, 只有外部事務(wù)結(jié)束后它才會被提交锌俱。