Spring之Transaction

什么是事務(wù)

事務(wù)是一系列操作組成的工作單元,該工作單元具有不可分割性十绑,一損俱損。滿足ACID(原子性榴啸,一致性孽惰,隔離性,持久性)

事務(wù)按分布式劃分可以分為本地事務(wù)鸥印,和分布式事務(wù)

分別由JDBC事務(wù)JTA事務(wù)與其對應(yīng)勋功。

Transaction其實在某些具體業(yè)務(wù)上,是相當(dāng)實用的利器库说。但是我在工作之前對他的認(rèn)識只是停留在概念的層面狂鞋,現(xiàn)在想想還是很有必要好好總結(jié)一下的。

事務(wù)最經(jīng)典的例子就是銀行轉(zhuǎn)賬問題潜的,A用戶轉(zhuǎn)賬5000元給B用戶骚揍,如果在不發(fā)生任何意外的情況下,那么是一點問題沒有的,但是如果這兩部操作中間出現(xiàn)了意外(例如發(fā)生了異常)信不,很有可能這500元只轉(zhuǎn)出了嘲叔,并沒有轉(zhuǎn)入。那么這個問題的根本原因是兩個操作在代碼層面來看是相互獨立的抽活,并不具備原子性導(dǎo)致的硫戈。Spring又是怎么解決這個問題的呢?

再來通過代碼層面分析一下這個問題下硕,轉(zhuǎn)出的時候丁逝,我們通過DataSource拿到一個Connection對象,當(dāng)執(zhí)行沒有異常的時候梭姓,直接提交事務(wù)霜幼,代碼并不知道還有轉(zhuǎn)入操作的存在。

所以spring針對這一點誉尖,如果在Service層的一個方法開啟了事務(wù)罪既,那么會關(guān)閉在這個方法中調(diào)用Dao方法自動提交事務(wù)的屬性,等到整個service執(zhí)行后再做提交铡恕,具體的步驟如下:

  1. 獲取DataSource對象
  2. 通過DataSource對象獲取對應(yīng)的Connection對象
  3. 關(guān)閉事務(wù)的自動提交機制野崇,在Connection對象中
  4. 把Connection對象綁定到當(dāng)前線程中
  5. 在Dao中通過取得當(dāng)前線程的Connection然后執(zhí)行操作
  6. 如果整個Service都o(jì)k則Commit驯用,否則進行rollback

事務(wù)的隔離機制

數(shù)據(jù)庫的并發(fā)的問題奖蔓,應(yīng)運而生:例如說臟讀以蕴,虛讀,第一類丟失更新祭刚,第二類丟失更新牌捷。

解決的辦法就是通過不同的隔離機制,進行隔離:

  • Read Uncommited
  • Read Commited
  • Repeatable Read
  • Serializable

Oracle 默認(rèn)使用Read Comited涡驮, Mysql默認(rèn)使用 Repeatable Read暗甥。

隔離機制越高,性能越差捉捅。

事務(wù)的傳播規(guī)則

在一個事務(wù)方法中撤防,調(diào)用了別的事務(wù),應(yīng)該按照什么規(guī)則進行傳遞棒口。

傳播規(guī)則一共分為七種:

現(xiàn)在有這樣一種情況A方法調(diào)用了B方法寄月。

  1. required:必須存在一個事務(wù),如果有事務(wù)无牵,則加入到該事務(wù)漾肮,如果沒有則新建。解讀:A如果有事務(wù)茎毁,B就用A的事務(wù)克懊,如果A沒有事務(wù),則B新建一個事務(wù)
  2. supports:如果有事務(wù),則用谭溉。沒有則不用墙懂。解讀:A如果有事務(wù),B就用A的扮念,A如果沒有垒在,B則不用事務(wù)。
  3. Mandatory:必須存在事務(wù)扔亥,當(dāng)前如果有事務(wù),則用谈为。沒有則直接報異常旅挤。解讀:A如果有事務(wù),B就用A的事務(wù)伞鲫,如果沒有粘茄,則直接報錯。
  4. required_new: 不管當(dāng)前是否存在事務(wù)秕脓,都會創(chuàng)建一個新的柒瓣,這個在平常比較多。
  5. not_supports: 以非事務(wù)方式執(zhí)行吠架,如果當(dāng)前存在事務(wù)芙贫,則將當(dāng)前事務(wù)掛起 解讀:A有自己的事務(wù),B不使用A的事務(wù)傍药,B不參與A事務(wù)的管理磺平。
  6. never:不支持事務(wù),當(dāng)前如果存在事務(wù)拐辽,則拋出異常拣挪。
  7. nested:寄生事務(wù)。如果內(nèi)部事務(wù)進行回滾俱诸,不會影響到外部事務(wù)菠劝,如果外部事務(wù)回滾了,內(nèi)部事務(wù)會被影響睁搭。

Spring對事務(wù)的支持

Spring的事務(wù)管理一定要在業(yè)務(wù)層上的

  • PlatformTransactionManager 根據(jù)TransactionBefination提供的事務(wù)信息赶诊,進行配置。是多種事務(wù)管理器的基類园骆。Hibernate使用的是HibernateTransactionManager甫何,Mybatis/JDBC使用的是DataSourceTransactionManager。PlatformTransactionManager 一共擁有三個方法:
    • getTransaction(TransactionDefination)遇伞,在當(dāng)前環(huán)境中取得一個事務(wù)辙喂,如果不存在,則新建。有點像是一種緩存機制
    • commit:提交事務(wù)
    • rollback:回滾事務(wù)
  • TransactionDefination:封裝了事務(wù)隔離級別巍耗,超時時間等秋麸。
  • TransactionStatus:封裝了事務(wù)具體運行的狀態(tài),是否是新開的事務(wù)炬太,是否已經(jīng)提交事務(wù)
Xml方式進行配置:

下方是Spring官網(wǎng)給的例子

//業(yè)務(wù)接口:
public interface FooService {

    Foo getFoo(String fooName);

    Foo getFoo(String fooName, String barName);

    void insertFoo(Foo foo);

    void updateFoo(Foo foo);

}
<!--xml文件關(guān)于事務(wù)的配置-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- 首先將剛剛的業(yè)務(wù)類注入進容器中 -->
    <bean id="fooService" class="x.y.service.DefaultFooService"/>

   <!-- 配置數(shù)據(jù)庫連接池灸蟆,因為連接池會作為屬性注入到TransactionManager中 -->
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
        <property name="url" value="jdbc:oracle:thin:@rj-t42:1521:elvis"/>
        <property name="username" value="scott"/>
        <property name="password" value="tiger"/>
    </bean>

    <!-- 配置PlatformTransactionManager -->
    <bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
  
  <!-- 配置transaction 具體的一些配置 -->
    <tx:advice id="txAdvice" transaction-manager="txManager">
        <!-- the transactional semantics... -->
        <tx:attributes>
            <!-- 如果是方法名以get作為開頭的,說明是查詢方法亲族,那么配置只讀操作-->
            <tx:method name="get*" read-only="true"/>
            <!-- 其他的增和改操作炒考,就是用默認(rèn)的即可-->
            <tx:method name="*"/>
        </tx:attributes>
    </tx:advice>
  
    <!-- 使用Aop把transactionManager作為對業(yè)務(wù)邏輯的增強操作 -->
    <aop:config>
        <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="fooServiceOperation"/>
    </aop:config> 

    <!-- other <bean/> definitions here -->

</beans>

<tx:advice/>中的一些詳細配置,官網(wǎng)也給出了相應(yīng)的一些說明霎迫,如下圖:

Attribute Required? Default Description
name Yes 事務(wù)管理的方法名稱斋枢,并且支持通配符,例如 get*, handle*, on*Event, 等等).
propagation No REQUIRED Transaction propagation behavior.
isolation No DEFAULT 事務(wù)的隔離級別知给,當(dāng)傳遞規(guī)則為 REQUIRED or REQUIRES_NEW才可以設(shè)置瓤帚,當(dāng)是默認(rèn)值default的時候,指的是使用數(shù)據(jù)庫隔離級別涩赢。其他四種都是Spring 通過代碼模擬出來的
timeout No -1 事務(wù)超時時間 (seconds)戈次,當(dāng)傳遞規(guī)則為 REQUIRED or REQUIRES_NEW才可以設(shè)置,默認(rèn)值-1代表使用數(shù)據(jù)庫本身的值筒扒,一般情況下怯邪,不需要進行修改。
read-only No false 一般對查詢進行設(shè)置只讀花墩,可以提升事務(wù)的效率擎颖。只應(yīng)用于 REQUIRED or REQUIRES_NEW.
rollback-for No java.lang.RunTimeException 遇到什么異常需要做事務(wù)的回滾,例如,com.foo.MyBusinessException,ServletException.
no-rollback-for No 遇到什么異常不做回滾,com.foo.MyBusinessException,ServletException.
Java注解方式

首先我們需要在配置類上观游,開啟對事務(wù)的支持搂捧,使用@EnableTransactionManagement

官網(wǎng)的例子:

@Transactional(readOnly = true)
public class DefaultFooService implements FooService {

    public Foo getFoo(String fooName) {
        // do something
    }

    // these settings have precedence for this method
    @Transactional(readOnly = false, propagation = Propagation.REQUIRES_NEW)
    public void updateFoo(Foo foo) {
        // do something
    }
}

@Transactional 注解可以用來放在實現(xiàn)類上,也可以放在接口上懂缕,最好是放在實現(xiàn)類上允跑。如果加在了實現(xiàn)類上,那么也就是說對這個類里的所有方法都支持開啟事務(wù)搪柑。如果有哪個類需要一些定制化的屬性聋丝,只需要在方法上再加上這個注解并且貼上定制的屬性即可。

@Transactional可以使用的屬性:

Property Type Description
value String
propagation enum: Propagation
isolation enum: Isolation 隔離級別的設(shè)置工碾,用于傳遞屬性為 REQUIRED or REQUIRES_NEW.
timeout int (in seconds of granularity) 事務(wù)超時時間用于傳遞屬性為REQUIRES_NEW.
readOnly boolean 是否為只讀. 用于傳遞屬性為 REQUIRES_NEW.
rollbackFor Array of Class objects, which must be derived from Throwable.
rollbackForClassName Array of class names. The classes must be derived from Throwable. 哪些異常類處罰會導(dǎo)致回滾(使用異常類名)
noRollbackFor Array of Class objects, which must be derived from Throwable. 哪些異常類處罰不會導(dǎo)致回滾(使用異常類)
noRollbackForClassName Array of String class names, which must be derived from Throwable. 哪些異常類處罰不會導(dǎo)致回滾(使用異常類名)

可以看出來這些屬性與xml配置的大同小異弱睦。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市渊额,隨后出現(xiàn)的幾起案子况木,更是在濱河造成了極大的恐慌垒拢,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,640評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件火惊,死亡現(xiàn)場離奇詭異求类,居然都是意外死亡,警方通過查閱死者的電腦和手機屹耐,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,254評論 3 395
  • 文/潘曉璐 我一進店門尸疆,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人惶岭,你說我怎么就攤上這事寿弱。” “怎么了按灶?”我有些...
    開封第一講書人閱讀 165,011評論 0 355
  • 文/不壞的土叔 我叫張陵症革,是天一觀的道長。 經(jīng)常有香客問我兆衅,道長,這世上最難降的妖魔是什么嗜浮? 我笑而不...
    開封第一講書人閱讀 58,755評論 1 294
  • 正文 為了忘掉前任羡亩,我火速辦了婚禮,結(jié)果婚禮上危融,老公的妹妹穿的比我還像新娘畏铆。我一直安慰自己,他們只是感情好吉殃,可當(dāng)我...
    茶點故事閱讀 67,774評論 6 392
  • 文/花漫 我一把揭開白布辞居。 她就那樣靜靜地躺著,像睡著了一般蛋勺。 火紅的嫁衣襯著肌膚如雪瓦灶。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,610評論 1 305
  • 那天抱完,我揣著相機與錄音贼陶,去河邊找鬼。 笑死巧娱,一個胖子當(dāng)著我的面吹牛碉怔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播禁添,決...
    沈念sama閱讀 40,352評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼撮胧,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了老翘?” 一聲冷哼從身側(cè)響起芹啥,我...
    開封第一講書人閱讀 39,257評論 0 276
  • 序言:老撾萬榮一對情侶失蹤锻离,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后叁征,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纳账,經(jīng)...
    沈念sama閱讀 45,717評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,894評論 3 336
  • 正文 我和宋清朗相戀三年捺疼,在試婚紗的時候發(fā)現(xiàn)自己被綠了疏虫。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,021評論 1 350
  • 序言:一個原本活蹦亂跳的男人離奇死亡啤呼,死狀恐怖卧秘,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情官扣,我是刑警寧澤翅敌,帶...
    沈念sama閱讀 35,735評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站惕蹄,受9級特大地震影響蚯涮,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜卖陵,卻給世界環(huán)境...
    茶點故事閱讀 41,354評論 3 330
  • 文/蒙蒙 一遭顶、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧泪蔫,春花似錦棒旗、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,936評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至餐曹,卻和暖如春逛拱,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背台猴。 一陣腳步聲響...
    開封第一講書人閱讀 33,054評論 1 270
  • 我被黑心中介騙來泰國打工橘券, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人卿吐。 一個月前我還...
    沈念sama閱讀 48,224評論 3 371
  • 正文 我出身青樓旁舰,卻偏偏與公主長得像,于是被迫代替她去往敵國和親嗡官。 傳聞我的和親對象是個殘疾皇子箭窜,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,974評論 2 355

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