Spring | 事務(wù)管理

一邓萨、簡介

事務(wù)管理是企業(yè)級應(yīng)用程序開發(fā)中必不可少的技術(shù)地梨,用來確保數(shù)據(jù)的完整性和一致性
菊卷。事務(wù)是一系列的動作,這些動作要么全部完成宝剖,要么全部不起作用洁闰。

比如去銀行取款,總共分兩個步驟万细,取出錢扑眉,卡里扣錢,如果你在取錢的時候赖钞,突然出現(xiàn)停電或者及其故障腰素,此時很有可能出現(xiàn)兩種情況,要么你取出錢雪营,但是卡里沒扣錢弓千,或者是,你沒取出錢献起,但是卡里白白扣了那么多錢洋访。這肯定是不允許的,因此征唬,使用事務(wù)捌显,可以通過回滾操作茁彭,將已經(jīng)進行的操作全部取消总寒,相當于返回到了你取出錢之前的狀態(tài)

事務(wù)的四個關(guān)鍵屬性(ACID):原子性、一致性理肺、隔離性摄闸、持久性

二、Spring中的事務(wù)管理器

Spring 從不同的事務(wù)管理 API 中抽象了一整套的事務(wù)機制妹萨,開發(fā)人員不必了解底層的事務(wù) API年枕,就可以利用這些事務(wù)機制。有了這些事務(wù)機制乎完,事務(wù)管理代碼就能獨立于特定的事務(wù)技術(shù)了

Spring事務(wù)管理器的接口是 org.springframework.transaction.PlatformTransactionManager熏兄,通過這個接口,Spring為各個平臺如JDBC树姨、Hibernate等都提供了對應(yīng)的事務(wù)管理器

三摩桶、JDBC中的事務(wù)

如果應(yīng)用程序中直接使用 JDBC 來進行持久化,DataSourceTransactionManager 會為你處理事務(wù)邊界帽揪。為了使用 DataSourceTransactionManager硝清,你需要使用如下的XML將其裝配到應(yīng)用程序的上下文定義中:

<!-- 配置事務(wù)管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>

配置文件中需要引用 JDBC 的 Bean 來進行配置。實際上转晰,DataSourceTransactionManager 是通過調(diào)用 java.sql.Connection 來管理事務(wù)芦拿,而后者是通過 DataSource 獲取到的士飒。通過調(diào)用連接的 commit() 方法來提交事務(wù),同樣蔗崎,事務(wù)失敗則通過調(diào)用 rollback() 方法進行回滾酵幕。

四、使用兩種方式來管理事務(wù)

使用@Transactional注解聲明式地管理事務(wù)

  • 在需要定義事務(wù)操作的方法上加上 @Transactional 注解缓苛,且只能標注共有方法
  • 在 Bean 配置文件中只需使用 <tx:annotation-driven> 元素裙盾,并為之指定事務(wù)管理器就可以了
  • 如果事務(wù)處理器的名稱是 transactionManager,就可以在 <tx:annotation-driven> 元素中省略 transaction-manager 屬性他嫡,這個元素會自動檢測該名稱的事務(wù)管理器
<!-- 啟用事務(wù)注解 -->
<tx:annotation-driven transaction-manager="transactionManager"/>


使用事務(wù)通知來聲明式的管理事務(wù)

  • 事務(wù)管理是一種橫切關(guān)注點
  • 使用 <tx:advice> 元素聲明事務(wù)通知番官,同時在里面設(shè)置事務(wù)的各種屬性
  • 通過 <aop:config> 配置事務(wù)切入點,由于事務(wù)通知在 <aop:config> 元素外部聲明的钢属,所以無法直接與切入點產(chǎn)生關(guān)聯(lián)徘熔,必須在 <aop:config> 元素里面聲明一個 <aop:advisor> (增強器)與切入點想聯(lián)系
  • 由于 Spring AOP 是基于代理的方法,因此只能增強公共方法
<!-- 1. 配置事務(wù)管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"></property>
</bean>
    
<!-- 2. 配置事務(wù)屬性 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 根據(jù)方法名指定事務(wù)的屬性 -->
        <tx:method name="purchase" propagation="REQUIRES_NEW"/>
        <!-- 指定 get 開頭的方法為只讀的 -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>
    
<!-- 3. 配置事務(wù)切入點, 以及把事務(wù)切入點和事務(wù)屬性關(guān)聯(lián)起來 -->
<aop:config>
    <!-- 配置切點表達式 -->
    <aop:pointcut expression="execution(* edu.just.spring.jdbc.transaction.BookShopService.*(..))" id="txPointCut"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>


五淆党、事務(wù)傳播屬性

當事務(wù)方法被另一個事務(wù)方法調(diào)用時酷师,必須指定事務(wù)應(yīng)該如何傳播,如:被調(diào)用的方法是在調(diào)用自己的方法所在事務(wù)中運行染乌,還是創(chuàng)建一個自己的新事務(wù)山孔,并在自己的新事務(wù)中運行。以下是就介紹幾種傳播行為:

  • REQUIRED:如果有事務(wù)在運行荷憋,當前的方法就在這個事務(wù)內(nèi)運行台颠;否則就創(chuàng)建一個新的事務(wù),并在自己的事務(wù)內(nèi)運行
  • REQUIRED_NEW:當前的方法必須啟動新事務(wù)勒庄,并在它自己的事務(wù)內(nèi)運行串前,如果運行自己事務(wù)同時還有其他事務(wù)在運行,應(yīng)該把其他事務(wù)暫時掛起
  • SUPPORTS:如果有事務(wù)在運行实蔽,當前的方法就在這個事務(wù)內(nèi)運行荡碾,否則它可以不運行在事務(wù)內(nèi)
  • NOT_SUPPORTED:當前的方法不應(yīng)該運行在事務(wù)中,如果有運行的事務(wù)局装,將它掛起
  • MANDATORY:當前的方法必須在事務(wù)內(nèi)部坛吁,如果沒有正在運行的事務(wù),就拋出異常
  • NESTED:如果有事務(wù)在運行铐尚,當前的方法就應(yīng)該在這個事務(wù)的嵌套事務(wù)內(nèi)運行

如何設(shè)置拨脉?
  1. 使用 @Transactional 注解
@Transactional(propagation=Propagation.REQUIRES_NEW)
@Override
public void purchase(String username, String isbn) {    
        ....
}


  1. 在事務(wù)通知中配置傳播屬性
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 根據(jù)方法名指定事務(wù)的屬性 -->
        <tx:method name="purchase" propagation="REQUIRES_NEW"/>
    </tx:attributes>
</tx:advice>

可以在 <tx:method> 元素中設(shè)置傳播事務(wù)屬性

五、并發(fā)事務(wù)所導(dǎo)致的問題

當同一個應(yīng)用程序或者不同應(yīng)用程序中的多個事務(wù)在同一個數(shù)據(jù)集上并發(fā)執(zhí)行時塑径,可能會出現(xiàn)許多意外的問題

  1. 臟讀:臟讀就是指當一個事務(wù)正在訪問數(shù)據(jù)女坑,并且對數(shù)據(jù)進行了修改,而這種修改還沒有提交到數(shù)據(jù)庫中统舀,這時匆骗,另外一個事務(wù)也訪問這個數(shù)據(jù)劳景,然后使用了這個數(shù)據(jù)。此時若這個數(shù)據(jù)進行回滾碉就,則事務(wù)讀取的數(shù)據(jù)就是臨時且無效的盟广。
  2. 不可重復(fù)讀:是指在一個事務(wù)內(nèi),多次讀同一數(shù)據(jù)瓮钥。在這個事務(wù)還沒有結(jié)束時筋量,對于兩個事務(wù),第一個事務(wù)先讀取了一個字段碉熄,然后第二個事務(wù)修改了該字段桨武,之后,第一個事務(wù)再次讀取了同一個字段锈津,那么兩次讀取到的值是不一樣的呀酸。這樣就發(fā)生了在一個事務(wù)內(nèi)兩次讀到的數(shù)據(jù)是不一樣的,因此稱為是不可重復(fù)讀琼梆。
  3. 幻讀:第一個事務(wù)從表中讀取了一個字段性誉,然后第二個事務(wù)在該表中插入了一些新的行,之后如果第一個事務(wù)再次讀取同一個表茎杂,會發(fā)現(xiàn)多出幾行错览,如同發(fā)僧侶幻覺一般

六、事務(wù)的隔離級別

理論上說煌往,事務(wù)應(yīng)該彼此完全隔離倾哺,以避免并發(fā)事務(wù)所導(dǎo)致的問題。然而携冤,那樣會對性能產(chǎn)生極大的影響悼粮,因此為事務(wù)必須按順序執(zhí)行闲勺。在實際開發(fā)中曾棕,為了提升性能,事務(wù)會以比較低的隔離級別來運行

  1. DEFAULT:使用底層數(shù)據(jù)庫的默認隔離級別菜循,對于大多數(shù)數(shù)據(jù)庫來說翘地,默認隔離級別為 READ_COMMITED,Mysql 的默認隔離級別是 REPEATABLE-READ
  2. READ_UNCOMMITEED:允許事務(wù)讀取未被其他事務(wù)提交的變更癌幕,會出現(xiàn)臟讀衙耕、不可重復(fù)度和幻讀
  3. READ_COMMITEED:只允許事務(wù)讀取已經(jīng)被其他事務(wù)提交的變更,可以避免臟讀勺远,但不可重復(fù)讀和幻讀可能出現(xiàn)
  4. REPEATABLE_READ:確保事務(wù)可以多次從一個字段中讀取相同的值橙喘,在這個事務(wù)持續(xù)期間,禁止其他事務(wù)對這個字段進行更新胶逢,可以避免臟讀和不可重復(fù)讀厅瞎,但是幻讀的問題依舊存在
  5. SERIALIZABLE:確保事務(wù)可以從一個表中讀取相同的行饰潜,在這個事務(wù)期間,禁止其他事務(wù)對改變執(zhí)行增和簸、刪彭雾、改操作,所有并發(fā)問題都可以避免锁保,但是性能低下

PS:Oracle 支持兩種事務(wù)隔離級別薯酝,READ_COMMITEEDSERIALIZABLE。MySql 支持4種事務(wù)隔離級別

如何設(shè)置爽柒?
  1. 用 @Transactional 注解
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED)
@Override
public void purchase(String username, String isbn) {
        ...
}

可以在 @Transactionalisolation 屬性中設(shè)置隔離級別

  1. 可以在 <tx:method> 元素中指定隔離級別
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 根據(jù)方法名指定事務(wù)的屬性 -->
        <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"/>
    </tx:attributes>
</tx:advice>


七吴菠、設(shè)置超時和只讀事務(wù)屬性

  1. 超時和只讀屬性可以在 @Transactional 注解中定義。超時屬性以秒為單位來計算
@Transactional(propagation=Propagation.REQUIRED, isolation=Isolation.READ_COMMITTED, readOnly=false, timeout=3)
@Override
public void purchase(String username, String isbn) {
        ...
}


  1. 也可以在 <tx:method> 中進行指定
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <!-- 根據(jù)方法名指定事務(wù)的屬性 -->
        <tx:method name="purchase" propagation="REQUIRES_NEW" isolation="READ_COMMITTED"/>
        <!-- 指定 get 開頭的方法為只讀的 -->
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>


參考

臟讀浩村、不可重復(fù)讀 共享鎖橄务、悲觀鎖 和 事務(wù)五種隔離級別
理解事務(wù)的4種隔離級別
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市穴亏,隨后出現(xiàn)的幾起案子蜂挪,更是在濱河造成了極大的恐慌,老刑警劉巖嗓化,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件棠涮,死亡現(xiàn)場離奇詭異,居然都是意外死亡刺覆,警方通過查閱死者的電腦和手機严肪,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來谦屑,“玉大人驳糯,你說我怎么就攤上這事∏獬龋” “怎么了酝枢?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長悍手。 經(jīng)常有香客問我帘睦,道長,這世上最難降的妖魔是什么坦康? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任竣付,我火速辦了婚禮,結(jié)果婚禮上滞欠,老公的妹妹穿的比我還像新娘古胆。我一直安慰自己,他們只是感情好筛璧,可當我...
    茶點故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布逸绎。 她就那樣靜靜地躺著妖滔,像睡著了一般。 火紅的嫁衣襯著肌膚如雪桶良。 梳的紋絲不亂的頭發(fā)上座舍,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機與錄音陨帆,去河邊找鬼曲秉。 笑死,一個胖子當著我的面吹牛疲牵,可吹牛的內(nèi)容都是我干的承二。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼纲爸,長吁一口氣:“原來是場噩夢啊……” “哼亥鸠!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起识啦,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤负蚊,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后颓哮,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體家妆,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年冕茅,在試婚紗的時候發(fā)現(xiàn)自己被綠了伤极。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,779評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡姨伤,死狀恐怖哨坪,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情乍楚,我是刑警寧澤当编,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站炊豪,受9級特大地震影響凌箕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜词渤,卻給世界環(huán)境...
    茶點故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望串绩。 院中可真熱鬧缺虐,春花似錦、人聲如沸礁凡。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至剪芍,卻和暖如春塞淹,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背罪裹。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工饱普, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人状共。 一個月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓套耕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親峡继。 傳聞我的和親對象是個殘疾皇子冯袍,可洞房花燭夜當晚...
    茶點故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容

  • Spring事務(wù)機制主要包括聲明式事務(wù)和編程式事務(wù),此處側(cè)重講解聲明式事務(wù)碾牌,編程式事務(wù)在實際開發(fā)中得不到廣泛使用康愤,...
    EnigmaXXX閱讀 668評論 0 0
  • 1 什么是事務(wù) 生活中關(guān)于事務(wù)有一個常見的場景,即銀行用戶轉(zhuǎn)賬舶吗。簡單的講翘瓮,轉(zhuǎn)賬可以分為下面 2 個步驟: 查看用戶...
    millions_chan閱讀 611評論 0 4
  • spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式。 編程式事務(wù)管理使用TransactionTemplate...
    熊熊要更努力閱讀 247評論 0 0
  • 三月 花開葉嫩 看到了嗎裤翩? 我給你寫的那首藏頭詩 我在等你的回答白手选! 六月 你終于笑著看我 說起了我的詩 坝辉呵扛!我終...
    奈何zh閱讀 911評論 0 2
  • 1. 使用git log命令查看所有的歷史版本,輸入q便可退出筐带,獲取某個歷史版本的id今穿,假設(shè)查到歷史版本的id是1...
    luckySmileBoy閱讀 7,702評論 0 2