Spring同時支持編程式事務策略和聲明式事務策略闹伪,大部分時候凭戴,我們都推薦采用聲明式事務策略函喉。使用聲明式事務策略的優(yōu)勢十分明顯:
聲明式事務能大大降低開發(fā)者的代碼書寫量,而且聲明式事務幾乎不影響應用的代碼麸塞。因此,不論底層事務策略如何變化涧衙,應用程序都無需任何改變
應用程序代碼無需任何事務處理代碼喘垂,可以更專注于業(yè)務邏輯的實現(xiàn)
Spring可對任何POJO的方法提供事務管理,而且Spring的聲明式事務管理無需容器的支持绍撞,可在任何環(huán)境下使用
EJB的CMT無法提供聲明式回滾規(guī)則正勒;而通過配置文件,Spring可指定事務在遇到特定異常時自動回滾傻铣。Spring不僅可在代碼中使用setRollbackOnly回滾事務章贞,也可在配置文件中配置回滾規(guī)則
由于Spring采用AOP的方式管理事務,因此非洲,可以在事務回滾動作中插入用戶自己的動作鸭限,而不僅僅是執(zhí)行系統(tǒng)默認的回滾
? ? 本文主要介紹Spring中聲明式事務管理的使用。
在Spring1.X中两踏,聲明式事務使用TransactionProxyFactoryBean來配置事務代理Bean败京。正如它的類名所暗示的,它是一個專門為目標Bean生成事務代理的工廠Bean梦染。既然TransactionProxyFactoryBean產(chǎn)生的是事務代理Bean赡麦,可見Spring的聲明式事務策略是基于Spring AOP的朴皆。
每個TransactionProxyFactoryBean為一個目標Bean生成一個事務代理Bean,事務代理的方法改寫了目標Bean的方法泛粹,就是在目標Bean的方法執(zhí)行之前加入開始事務遂铡,在目標Bean的方法正常結(jié)束之前提交事務,如果遇到特定異常則回滾晶姊。
TransactionProxyFactoryBean創(chuàng)建事務代理時扒接,需要了解當前事務所處的環(huán)境,該環(huán)境屬性通過PlatformTransactionManager實例(其實現(xiàn)類的實例)傳入们衙,而相關(guān)事務規(guī)則則在該Bean定義中給出钾怔。下面是一個簡單的持久化測試程序,該程序插入兩條數(shù)據(jù)蒙挑,這兩條數(shù)據(jù)完全相同蒂教,將違反唯一鍵約束:
上面的程序中,兩次update語句將會違反主鍵約束——該行代碼將會引發(fā)異常脆荷,如果在沒有事務的環(huán)境下凝垛,前一條代碼會向數(shù)據(jù)庫中插入一條記錄;但如果在增加了事務控制的環(huán)境下蜓谋,則這兩條語句是一個整體梦皮,因為第二條語句插入失敗將導致第一條插入的記錄也被回滾。下面是在Spring配置文件中配置該測試程序桃焕,并使用TransactionProxyFactoryBean為它們配置事務代理:
剑肯。配置事務代理(如上面的newsDaoTransProxy)時需要傳入一個事務管理器,一個目標Bean观堂,并指定該事務代理的事務屬性让网。事務屬性由transactionAttributes屬性指定。上面事務屬性只有一條事務傳播規(guī)則师痕,該規(guī)則制定對于所有方法都使用PROPAGATION_REQUIRED的傳播規(guī)則溃睹。Spring支持的事務傳播規(guī)則如下:
PROPAGATION_MANDATORY:要求調(diào)用該方法的線程必須處于事務環(huán)境中,否則拋出異常
PROPAGATION_NESTED:如果執(zhí)行該方法的線程已處于事務環(huán)境下胰坟,依然啟動新的事務因篇,方法在嵌套的事務里執(zhí)行。如果執(zhí)行方法的線程為處于事務中笔横,也啟動新的事務竞滓,然后執(zhí)行該方法,此時與PROPAGATION_REQUIRED相同
PROPAGATION_NEVER:不允許調(diào)用該方法的線程處于事務環(huán)境下吹缔,如果調(diào)用該方法的線程處于事務環(huán)境下商佑,則拋出異常
PROPAGATION_NOT_SUPPORTED:如果調(diào)用該方法的線程處在事務中,則暫停當前事務厢塘,然后執(zhí)行該方法
PROPAGATION_REQUIRED:要求在事務環(huán)境中執(zhí)行該方法茶没,如果當前執(zhí)行的線程已處于事務中肌幽,則直接調(diào)用;如果當前執(zhí)行線程不處于事務中礁叔,則啟動新的事務后執(zhí)行該方法
PROPAGATION_REQUIRES_NEW:要求在事務環(huán)境中執(zhí)行該方法牍颈,如果當前執(zhí)行的線程已處于事務中迄薄,則暫停當前事務琅关,啟動新事務后執(zhí)行該方法;如果當前執(zhí)行線程不處于事務中讥蔽,則啟動新的事務后執(zhí)行該方法
PROPAGATION_SUPPORTS:如果當前執(zhí)行線程處于事務中涣易,則使用當前事務;不過不在事務中冶伞,則不使用事務
????主程序中主要獲取了定義的NewsDao類型的Bean新症,并調(diào)用其insert方法,下面是主程序
上面的第4行中獲取了newsDaoTransProxy Bean响禽,該Bean已經(jīng)不在是NewsDaoImpl類的實例了徒爹,它只是Spring容器創(chuàng)建的事務代理,該事務代理以NewsDaoImpl實例為目標對象芋类,且該目標對象也實現(xiàn)了NewsDao接口(與NewsDaoImpl實現(xiàn)了相同的接口)隆嗅,故代理對象也可以當成NewsDao實例來使用。運行上面的程序侯繁,將出現(xiàn)一個異常胖喳,而且insert方法所執(zhí)行的兩條SQL語句全部回滾——因為事務控制的緣故。
????當我們使用TransactionProxyFactoryBean為目標Bean配置了事務代理以后贮竟,SpringAOP將會把負責事務操作的增強處理織入目標Bean的業(yè)務方法當中丽焊。事實上,Spring不僅支持對接口的代理咕别,整合CGLIB后技健,Spring甚至可以對具體類生成代理,只要設(shè)置proxyTargetClass屬性為true即可惰拱。如果目標Bean沒有實現(xiàn)任何接口凫乖,proxyTargetClass屬性默認被設(shè)為true,此時Spring會對具體類生成代理弓颈。當然通常建議面向接口編程帽芽,而不要面向具體的實現(xiàn)類編程。