1. 程式人生 > >Spring事務總結---事務概述及Spring事務的基本使用(完整)

Spring事務總結---事務概述及Spring事務的基本使用(完整)

 一、事務概述

   這一節內容純粹是為了寫而寫的,權當溫習資料庫知識和熟悉下怎麼寫部落格了,誰讓自己菜呢。:)

   看了許多別的部落格和資料,事務兩個字都快不認識了,那麼其實事務的概念很簡單,可以理解為一件事情,在計算機裡,它就是一個操作序列。

   它相比於普通的事情不同的是,它必須服從ISO/IEC指定的ACID原則。

   A(Aotomicity)原子性,簡單的說就是要麼全部一起做完,要麼都不做,即事務的不可分割性,若非使用特殊手段,如catch某些子事務的exception,否則當其中一個子事務失敗,其他事務都將一起回滾。

   C(Consistency)一致性,即其保證是從一個正確的狀態,轉換成另一種正確的狀態,即操作後資料不會被破壞,如轉賬時不會出現一方扣了錢而另一方卻收不到的狀況。

   I(Isolation)隔離性,在事務提交之前,它可能的結果不應該顯示給其他事務。舉個例子,如果一個事務為一個銀行需要存入100元后存入200元,那當然不可以在存入100元后,就例項化到資料庫被別的事務讀取了存入100元后的結果,如果在存入200元時發生回滾不就出大事了嘛。所謂的隔離,就是需要保證各個事務之間是沒有相互干擾的。

   D(Durability)永續性,其結果將正確的永久儲存在資料庫中,其他事務的失敗不會對其造成影響。



    以上四個特性,經常受到討論和爭辯的莫過於一致性和隔離性了。所謂魚與熊掌不可兼得,當我們需要兼顧所有的特性,可想而知,當安全性越高,其操作的顧忌和檢查越多,效能也就越差。所以對於一致性和隔離性,又有著不同的規範等級。(垃圾文字功底)

    權衡之下可能出現的問題

    1、髒讀,即讀到不乾淨的資料。

     例子:(例子原址)

    1)Mary的原工資為1000, 財務人員將Mary的工資改為了8000(但未提交事務) 
    2)Mary讀取自己的工資 ,發現自己的工資變為了8000,歡天喜地! 
    3)而財務發現操作有誤,回滾了事務,Mary的工資又變為了1000, 像這樣,Mary記取的工資數8000是一個髒資料。

    2、不可重複讀,即在同一個事務中,重複讀取卻有不同的結果。

    例子:(例子原址)

    1)在事務A中,Mary 讀取了自己的工資為1000,操作並沒有完成 
    2)在事務B中,這時財務人員修改了Mary的工資為2000,並提交了事務. 
    3)在事務A中,Mary 再次讀取自己的工資時,工資變為了2000 

    3、幻讀,即在同一事務中,可讀取到其他事務提交後的結果,造成疑惑。

    例子:(例子原址)

    1)A把所有的“黑色”改為“白色”

    2)B把所有的“紅色”改為“黑色”

    3)A再查詢黑色,卻發現還有一批。



    隔離性的四個級別

    1、READ_UNCOMMITED(未授權讀取),即可以讀到未提交的資料。

    附上一個別人寫的生動的例子

    公司發工資了,領導把5000元打到singo的賬號上,但是該事務並未提交,而singo正好去檢視賬戶,發現工資已經到賬,是5000元整,非常高 興。可是不幸的是,領導發現發給singo的工資金額不對,是2000元,於是迅速回滾了事務,修改金額後,將事務提交,最後singo實際的工資只有 2000元,singo空歡喜一場。(原址)

    2、READ_COMMITED(授權讀取),即其保證不會讀到未提交的事務,但會造成不可重複讀。

    附上一個別人寫的生動的例子

    singo拿著工資卡去消費,系統讀取到卡里確實有2000元,而此時她的老婆也正好在網上轉賬,把singo工資卡的2000元轉到另一賬戶,並在 singo之前提交了事務,當singo扣款時,系統檢查到singo的工資卡已經沒有錢,扣款失敗,singo十分納悶,明明卡里有錢,為 何......

    出現上述情況,即我們所說的不可重複讀 ,兩個併發的事務,“事務A:singo消費”、“事務B:singo的老婆網上轉賬”,事務A事先讀取了資料,事務B緊接了更新了資料,並提交了事務,而事務A再次讀取該資料時,資料已經發生了改變。(原址)
    3、REPEATABLE_READ(可重複讀),即當讀取時,不能進行更新。

     附上一個別人寫的生動的例子

    當singo拿著工資卡去消費時,一旦系統開始讀取工資卡資訊(即事務開始),singo的老婆就不可能對該記錄進行修改,也就是singo的老婆不能在此時轉賬。

    雖然Repeatable read避免了不可重複讀,但還有可能出現幻讀。

    singo的老婆工作在銀行部門,她時常通過銀行內部系統檢視singo的信用卡消費記錄。有一天,她正在查詢到singo當月信用卡的總消費金額(select sum(amount) from transaction where month = 本月)為80元,而singo此時正好在外面胡吃海塞後在收銀臺買單,消費1000元,即新增了一條1000元的消費記錄(insert transaction ... ),並提交了事務,隨後singo的老婆將singo當月信用卡消費的明細列印到A4紙上,卻發現消費總額為1080元,singo的老婆很詫異,以為出現了幻覺,幻讀就這樣產生了。

    注:Mysql的預設隔離級別就是Repeatable read。(原址)

    4、SERIALIZABLE(序列化),最高級別,在該級別下,事務順序執行,那也就不會出現上面的問題了。

    這四個規範,從上至下安全性越高,效能越差。

    附一張哪都能看到的表

事務隔離級別 髒讀 不可重複讀 幻讀
READ_UNCOMMITED Y Y Y
READ_COMMITED N Y Y
REPEATABLE_READ N N Y
SERIALIZABLE N N N




二、Spring事務用法

1、xml配置(搬運總結自開濤大神)

<!-- 事務管理的核心是事務管理器抽象,對於不同的資料訪問框架(如Hibernate)通過實現策略介面PlatformTransactionManager,從而能支援各種資料訪問框架的事務管理-->
<bean id="txManager"
      class="org.springframework.orm.hibernate3.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice transaction-manager="txManager" id="txAdvice">
    <tx:attributes>
    <!--表示將攔截以add開頭的方法,被攔截的方法將應用配置的事務屬性:propagation表示傳播行為級別,預設是Required,isolation表示隔離級別
      name:定義與事務屬性相關聯的方法名,將對匹配的方法應用定義的事務屬性,可以使用“*”萬用字元來匹配一組或所有方法,如“save*”將匹配以save開頭的方法,而“*”將匹配所有方法;
      propagation:事務傳播行為定義,預設為“REQUIRED”,表示Required,其值可以通過TransactionDefinition的靜態傳播行為變數的“PROPAGATION_”後邊部分指定,如“TransactionDefinition.PROPAGATION_REQUIRED”可以使用“REQUIRED”指定;
      isolation:事務隔離級別定義;預設為“DEFAULT”,其值可以通過TransactionDefinition的靜態隔離級別變數的“ISOLATION_”後邊部分指定,如“TransactionDefinition. ISOLATION_DEFAULT”可以使用“DEFAULT”指定:
      timeout:事務超時時間設定,單位為秒,預設-1,表示事務超時將依賴於底層事務系統;
      read-only:事務只讀設定,預設為false,表示不是隻讀;
      rollback-for:需要觸發回滾的異常定義,以“,”分割,預設任何RuntimeException 將導致事務回滾,而任何Checked Exception 將不導致事務回滾;異常名字定義和TransactionProxyFactoryBean中含義一樣
      no-rollback-for:不被觸發進行回滾的 Exception(s);以“,”分割;異常名字定義和TransactionProxyFactoryBean中含義一樣; -->
        <tx:method name="add*" />
    <:attributes>
<:advice>

<aop:config>
    <!--切入點定義,定義名為"myPointcut"的aspectj切入點,切入點表示式為"execution(* com..zhw.service..*.*(..))"表示攔截com包及子包下的zhw. service包及子包下的任何類的任何方法-->
    <aop:pointcut id="myPointcut" expression="execution(* com..zhw.service..*.*(..))" />
    <!--切入點為myPointcut,通知為txAdvice。-->
    <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
</aop:config>
    個人覺得xml配置的方式有點過於粗暴,在有事務巢狀的情況下有點難以處理(對我這種比較懶的人)。

2、Annotation宣告

<!--在xml配置檔案中開啟註解事務管理支援即可-->
<tx:annotation-driven/>
    其具有三個屬性

transaction-manager:指定事務管理器名字,預設為transactionManager

proxy-target-class:預設為false,false使用jdk動態代理,若為true則使用cglibs代理。設定為JDK代理和CGLIBS代理的主要區別是,使用JDK代理,@Transactional註釋可以作用在介面和類及其方法上,而CGLIBS只能只用在類上,為了避免疏忽,建議就寫在類上而不是介面上,而且,寫在介面上事務是不支援繼承的。

order:定義事務通知順序,預設將順序決定權交給AOP處理。

    在配置檔案中開啟註解事務管理後我們就可以使用@Transcational註釋用於事務管理了。

@Transcational
public class SuperServiceImpl implements SuperService{

    public void add();

}


@Transactional
public class SubServiceImpl extends SuperServiceImpl implements SubService{

    public void update();
}
    以上是最常用的用法:

    1、將@Transactional註釋作用在類上,預設該類所有方法都加入事務

    2、將@Transactional註釋作用在父類上,其可以被子類整合。


   @Transactional註釋有許多自定義的屬性使他的功能更加豐富。

value:指定事務管理器,用於支援多事務管理器環境

isolation:指定事務隔離級別,預設『DEFAULT』

readOnly:事務是否只讀,預設false。(即該事務開始後,其他事務所提交的資料,對該事務來說不可見,常用於多條查詢語句在同一事務的情況)

timeout:事務超時時間,單位:秒。預設-1,表示超時將依賴於底層事務系統。

rollbackFor:指定一組異常類,遇到該異常將進行回滾,如若沒有指定,那麼將只會對unchecked異常進行回滾,而checked異常將不會回滾。

rollbackForClassname:作用同上。

noRollbackFor:指定某異常類,遇到該異常不回滾事務。

noRollbackForClassname:作用同上。

    注意事項:

    1、@Transactional註釋只能作用於public方法上,其他修飾將被忽略。

    2、如果在介面,類,和方法上都指定了@Transactional註釋,則優先順序為方法->類->介面

    3、建議只在類上加@Transactional註釋,而不是介面上。

    4、預設只會對unchecked異常進行回滾,最常見的為RuntimeException及其各種子類。

    那麼Spring事務基本的使用方法就醬了 : ),目測已經可以滿足百分之八九十需求了。