Spring事務(wù)管理

1. 概念

什么是事務(wù)?事務(wù)指的是邏輯上的一組操作泵督,這組操作要么全部成功皮迟,要么全部失敗。

事務(wù)包括四大特性(ACID):原子性(Atomicity)辅搬、一致性(Consistency)唯沮、隔離性(Isolation)、持久性(Durability)

  1. 原子性:指事務(wù)是一個不可分割的工作單位堪遂,事務(wù)中的操作要么都發(fā)生介蛉,要么都不發(fā)生。
  2. 一致性:指事務(wù)前后數(shù)據(jù)的完整性必須保持一致溶褪。
  3. 隔離性:指多個用戶并發(fā)訪問數(shù)據(jù)庫時币旧,一個用戶的事務(wù)不能被其他用戶的事務(wù)所干擾,多個并發(fā)事務(wù)之間的數(shù)據(jù)要相互隔離猿妈。
  4. 持久性:指一個事務(wù)一旦被提交吹菱,它對數(shù)據(jù)庫中的數(shù)據(jù)的改變就是永久的,即使數(shù)據(jù)庫發(fā)生故障也不應(yīng)該對其有任何影響彭则。

2. 事務(wù)的API

2.1 接口介紹

Spring對事務(wù)管理提供了接口支持鳍刷,主要包括3個高層抽象的接口:

  1. PlatformTransactionManager事務(wù)管理器
  2. TransactionDefinition 事務(wù)定義信息(隔離、傳播俯抖、超時输瓜、只讀)
  3. TransactionStatus事務(wù)具體的運(yùn)行狀態(tài)信息(是否新事務(wù)、是否有保存點。前痘。凛捏。)
Spring事務(wù)主要接口
2.2 PlatformTransactionManager接口

Spring為不同的持久化框架提供了不同的PlatformTransactionManager接口實現(xiàn):

PlatformTransactionManager主要實現(xiàn)
具體實現(xiàn) 說明
org.springframework.jdbc.datasource.DataSourceTransactionManager 使用Spring JDBC或Mybatis進(jìn)行持久化數(shù)據(jù)是使用
org.springframework.orm.hibernate5.HibernateTransactionManager 使用Hibernate5.x版本進(jìn)行持久化數(shù)據(jù)時使用
org.springframework.orm.jpa.JpaTransactionManager 使用JPA進(jìn)行持久化時使用
org.springframework.orm.jdo.JdoTransactionManager 當(dāng)持久化機(jī)制是Jdo時使用
org.springframework.transaction.jta.JtaTransactionManager 使用一個JTA實現(xiàn)來管理事務(wù),在一個事務(wù)跨越多個資源時必須使用
2.3 TransactionDefinition接口
TransactionDefinition接口

TransactionDefinition接口中主要定義了事務(wù)的傳播行為getPropagationBehavior()芹缔、事務(wù)的隔離級別getIsolationLevel()坯癣、超時時間getTimeout()、是否只讀isReadOnly()最欠、事務(wù)名稱getName()

2.3.1 TransactionDefinition定義事務(wù)隔離級別

我們知道事務(wù)4個特性中有一個隔離性示罗,如果不考慮隔離性的的話,會引發(fā)一些安全問題:臟讀芝硬、不可重復(fù)讀蚜点、幻讀

  1. 臟讀:一個事務(wù)讀取了另一個事務(wù)改寫但還未提交的數(shù)據(jù),如果這些數(shù)據(jù)被回滾拌阴,則讀到的數(shù)據(jù)是無效的绍绘。
  2. 不可重復(fù)讀:在同一事務(wù)中,多次讀取同一數(shù)據(jù)返回的結(jié)果有所不同
  3. 幻讀:一個事務(wù)讀取了幾行記錄后迟赃,另一個事務(wù)插入一些記錄陪拘,幻讀就發(fā)生了。在后來的查詢中纤壁,第一個事務(wù)就會發(fā)現(xiàn)有些原來沒有的記錄

隔離級別就是用來解決上述各種問題的左刽,隔離級別有4種(上圖中的ISOLATION_*** 除了ISOLATION_DEFAULT):

隔離級別 含義
DEFAULT 使用后端數(shù)據(jù)庫默認(rèn)的隔離級別(Spring中的選擇項)
READ_UNCOMMITTED 允許你讀取還未提交的改變了的數(shù)據(jù)∽妹剑可能導(dǎo)致臟欠痴、幻、不可重復(fù)讀
READ_COMMITTED 允許在并發(fā)事務(wù)已經(jīng)提交后讀取秒咨±桑可防止臟讀,但幻讀拭荤、不可重復(fù)讀仍可發(fā)生
REPEATABLE_READ 對相同的字段的多次讀取是一致的茵臭,除非數(shù)據(jù)被事務(wù)本身改變【耸溃可防止臟旦委、不可重復(fù)讀,但幻讀仍可能發(fā)生
SERIALIZABLE 完全服從ACID的隔離級別雏亚,確保不發(fā)送臟缨硝、幻、不可重復(fù)讀罢低。這仔所有的隔離級別中是最慢的查辩,它是典型的通過完全鎖定在事務(wù)中涉及的數(shù)據(jù)表完成的胖笛。
2.3.2 TransactionDefinition定義事務(wù)傳播行為

事務(wù)的傳播行為解決的是業(yè)務(wù)層方法之間調(diào)用的時事務(wù)的傳遞問題。

一般我們的系統(tǒng)會分為3層:Web層宜岛、業(yè)務(wù)層Service长踊、持久層DAO;假設(shè)有兩個業(yè)務(wù)類ServiceAServiceB萍倡,ServiceA中有方法aaa(),ServiceB中有方法bbb(),有一個業(yè)務(wù)邏輯需要調(diào)用ServiceA.aaa()ServiceB.bbb()才能完成身弊,現(xiàn)在aaa()方法里有事務(wù),bbb()方法里也有事務(wù)列敲,那到底要用哪個呢阱佛,這就涉及到了事務(wù)的傳播行為。

事務(wù)的傳播行為有7種(上圖中的PROPAGATION_***):

隔離級別 含義
PROPAGATION_REQUIRED 支持當(dāng)前事務(wù)戴而,如果不存在凑术,就新建一個
PROPAGATION_SUPPORTS 支持當(dāng)前事務(wù),如果不存在所意,就不使用事務(wù)
PROPAGATION_MANDATORY 支持當(dāng)前事務(wù)淮逊,如果不存在,拋出異常
PROPAGATION_REQUIRES_NEW 如果有事務(wù)存在扶踊,掛起當(dāng)前事務(wù)壮莹,創(chuàng)建一個新的事務(wù)
PROPAGATION_NOT_SUPPORTED 以非事務(wù)的方式運(yùn)行,如果有事務(wù)存在姻檀,掛起當(dāng)前事務(wù)
PROPAGATION_NEVER 以非事務(wù)的方式運(yùn)行,如果有事務(wù)存在涝滴,拋出異常
PROPAGATION_NESTED 如果當(dāng)前事務(wù)存在绣版,則嵌套事務(wù)執(zhí)行
2.4 TransactionStatus接口
TransactionStatus接口

事務(wù)本身會存在一些狀態(tài)信息,而TransactionStatus接口里面提供了一些方法歼疮,通過這些方法可以獲得事務(wù)相應(yīng)的狀態(tài)杂抽。

isNewTransaction():判斷是否是一個新的事務(wù)
hasSavepoint():是否存在保存點
setRollbackOnly():設(shè)置為只回滾
isRollbackOnly():是否為只回滾
isCompleted():是否已完成

3. 編程式事務(wù)管理(不常用)

編程式事務(wù)管理使用TransactionTemplate模板來控制事務(wù)。TransactionTemplate的重要方法就是 execute方法韩脏,此方法調(diào)用 TransactionCallback 進(jìn)行處理缩麸。實際上我們需要處理的事情全部都是在TransactionCallback中編碼的,我們可以定義一個類并實現(xiàn)此接口赡矢,然后作為 TransactionTemplate.execute的參數(shù)杭朱。把需要完成的事情放到doInTransaction中,并且傳入一個 TransactionStatus參數(shù)吹散,此參數(shù)是來調(diào)用回滾的弧械。demo如下:

spring配置文件springDemo1.xml

    <?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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.1.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.1.xsd"
       default-lazy-init="true">

    <description>Spring Configuration</description>

    <!-- 加載配置屬性文件 -->
    <context:property-placeholder ignore-unresolvable="true" location="classpath:jdbc.properties" />

    <!-- 使用Annotation自動注冊Bean base-package 如果多個,用“,”分隔-->
    <context:component-scan base-package="com.zhoubg.spring.transaction.demo1" />


    <!-- 數(shù)據(jù)源配置, 使用 Druid 數(shù)據(jù)庫連接池 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
        <!-- 數(shù)據(jù)源驅(qū)動類可不寫空民,Druid默認(rèn)會自動根據(jù)URL識別DriverClass -->
        <property name="driverClassName" value="${jdbc.driver}" />
        <!-- 基本屬性 url刃唐、user、password -->
        <property name="url" value="${jdbc.url}" />
        <property name="username" value="${jdbc.username}" />
        <property name="password" value="${jdbc.password}" />
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <!-- ==================================1.編程式的事務(wù)管理=============================================== -->

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

    <!-- 配置事務(wù)管理的模板:Spring為了簡化事務(wù)管理的代碼而提供的類 -->
    <bean id="transactionTemplate" class="org.springframework.transaction.support.TransactionTemplate">
        <property name="transactionManager" ref="transactionManager"/>
    </bean>
</beans>

模擬業(yè)務(wù)方法AccountServiceImpl.transfer:

/**
     * 模擬轉(zhuǎn)賬操作
     * @param out   :轉(zhuǎn)出賬號
     * @param in    :轉(zhuǎn)入賬號
     * @param money :轉(zhuǎn)賬金額
     */
    public void transfer(final String out,final String in,final Double money) {

        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try { //具體業(yè)務(wù)代碼
                    accountDaoImpl.outMoney(out,money); //out賬戶出賬
                    //int i = 1/0;
                    accountDaoImpl.inMoney(in,money);// in賬戶入賬
                }catch (Exception e){
                    status.setRollbackOnly(); //設(shè)置回滾
                    e.printStackTrace();
                }
            }
        });
    }

4. 聲明式事務(wù)管理

4.1 聲明式事務(wù)管理方式一:基于TransactionProxyFactoryBean的方式

spring配置文件springDemo2.xml關(guān)鍵配置:

    <!-- ==================================2.使用XML配置聲明式的事務(wù)管理(原始方式)=============================================== -->

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

    <!-- 配置業(yè)務(wù)層的代理 -->
    <bean id="accountServiceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
        <!-- 配置目標(biāo)對象 -->
        <property name="target" ref="accountServiceImpl" />
        <!-- 注入事務(wù)管理器 -->
        <property name="transactionManager" ref="transactionManager"></property>
        <!-- 注入事務(wù)的屬性 -->
        <property name="transactionAttributes">
            <props>
                <!--
                    prop的格式:
                        * PROPAGATION   :事務(wù)的傳播行為
                        * ISOTATION     :事務(wù)的隔離級別
                        * readOnly      :只讀
                        * -EXCEPTION    :發(fā)生哪些異常回滾事務(wù)
                        * +EXCEPTION    :發(fā)生哪些異常不回滾事務(wù)
                 -->
                <prop key="transfer">PROPAGATION_REQUIRED</prop>
                <!-- <prop key="transfer">PROPAGATION_REQUIRED,readOnly</prop> -->
                <!-- <prop key="transfer">PROPAGATION_REQUIRED,+java.lang.ArithmeticException</prop> -->
            </props>
        </property>
    </bean>

模擬業(yè)務(wù)方法AccountServiceImpl.transfer:

  public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }
4.2 聲明式事務(wù)管理方式二:基于AspectJ的XML方式

spring配置文件springDemo3.xml關(guān)鍵配置:

    <!-- ==================================3.使用XML配置聲明式的事務(wù)管理,基于tx/aop=============================================== -->

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

    <!-- 配置事務(wù)的通知 -->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <!--
                propagation :事務(wù)傳播行為
                isolation   :事務(wù)的隔離級別
                read-only   :只讀
                rollback-for:發(fā)生哪些異郴ⅲ回滾
                no-rollback-for :發(fā)生哪些異常不回滾
                timeout     :過期信息
             -->
            <tx:method name="transfer" propagation="REQUIRED" />
        </tx:attributes>
    </tx:advice>

    <!-- 配置切面 -->
    <aop:config>
        <!-- 配置切入點 -->
        <aop:pointcut expression="execution(* com.zhoubg.spring.transaction..demo3.AccountService+.*(..))" id="pointcut1"/>
        <!-- 配置切面 -->
        <aop:advisor advice-ref="txAdvice" pointcut-ref="pointcut1"/>
    </aop:config>

模擬業(yè)務(wù)方法AccountServiceImpl.transfer:

public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }
4.3 聲明式事務(wù)管理方式三:基于注解的方式(推薦)

這種方式是基于@Transactional注解的衔瓮,簡單易用,更清爽抖甘,是推薦的使用方式热鞍。

@Transactional 可以作用于接口、接口方法单山、類以及類方法上碍现。當(dāng)作用于類上時,該類的所有 public方法將都具有該類型的事務(wù)屬性米奸,同時昼接,我們也可以在方法級別使用該標(biāo)注來覆蓋類級別的定義。

@Transactional的屬性:

屬性 類型 描述
value String 可選的限定描述符悴晰,指定使用的事務(wù)管理器
propagation enum: Propagation 可選的事務(wù)傳播行為設(shè)置
isolation enum: Isolation 可選的事務(wù)隔離級別設(shè)置
readOnly boolean 讀寫或只讀事務(wù)慢睡,默認(rèn)讀寫
timeout int (in seconds granularity) 事務(wù)超時時間設(shè)置
rollbackFor Class對象數(shù)組,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類數(shù)組
rollbackForClassName 類名數(shù)組铡溪,必須繼承自Throwable 導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組
noRollbackFor Class對象數(shù)組漂辐,必須繼承自Throwable 不會導(dǎo)致事務(wù)回滾的異常類數(shù)組
noRollbackForClassName 類名數(shù)組,必須繼承自Throwable 不會導(dǎo)致事務(wù)回滾的異常類名字?jǐn)?shù)組

spring配置文件springDemo4.xml關(guān)鍵配置:

    <!-- ==================================4.使用注解配置聲明式事務(wù)============================================ -->

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

    <!-- 開啟注解事務(wù) -->
    <tx:annotation-driven transaction-manager="transactionManager"/>

模擬業(yè)務(wù)方法AccountServiceImpl.transfer:

    @Transactional(readOnly = false)
    public void transfer(final String out,final String in,final Double money) {
        accountDaoImpl.outMoney(out,money);
        accountDaoImpl.inMoney(in,money);
    }

以上示例源碼:learn-spring-transaction

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末棕硫,一起剝皮案震驚了整個濱河市髓涯,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌哈扮,老刑警劉巖纬纪,帶你破解...
    沈念sama閱讀 212,029評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異滑肉,居然都是意外死亡包各,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,395評論 3 385
  • 文/潘曉璐 我一進(jìn)店門靶庙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來问畅,“玉大人,你說我怎么就攤上這事六荒』つ罚” “怎么了?”我有些...
    開封第一講書人閱讀 157,570評論 0 348
  • 文/不壞的土叔 我叫張陵掏击,是天一觀的道長签则。 經(jīng)常有香客問我,道長铐料,這世上最難降的妖魔是什么渐裂? 我笑而不...
    開封第一講書人閱讀 56,535評論 1 284
  • 正文 為了忘掉前任豺旬,我火速辦了婚禮,結(jié)果婚禮上柒凉,老公的妹妹穿的比我還像新娘族阅。我一直安慰自己,他們只是感情好膝捞,可當(dāng)我...
    茶點故事閱讀 65,650評論 6 386
  • 文/花漫 我一把揭開白布坦刀。 她就那樣靜靜地躺著,像睡著了一般蔬咬。 火紅的嫁衣襯著肌膚如雪鲤遥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,850評論 1 290
  • 那天林艘,我揣著相機(jī)與錄音盖奈,去河邊找鬼。 笑死狐援,一個胖子當(dāng)著我的面吹牛钢坦,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播啥酱,決...
    沈念sama閱讀 39,006評論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼爹凹,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了镶殷?” 一聲冷哼從身側(cè)響起禾酱,我...
    開封第一講書人閱讀 37,747評論 0 268
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎绘趋,沒想到半個月后宇植,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,207評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡埋心,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,536評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了忙上。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片拷呆。...
    茶點故事閱讀 38,683評論 1 341
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖疫粥,靈堂內(nèi)的尸體忽然破棺而出茬斧,到底是詐尸還是另有隱情,我是刑警寧澤梗逮,帶...
    沈念sama閱讀 34,342評論 4 330
  • 正文 年R本政府宣布项秉,位于F島的核電站,受9級特大地震影響慷彤,放射性物質(zhì)發(fā)生泄漏娄蔼。R本人自食惡果不足惜怖喻,卻給世界環(huán)境...
    茶點故事閱讀 39,964評論 3 315
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望岁诉。 院中可真熱鬧锚沸,春花似錦、人聲如沸涕癣。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,772評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽坠韩。三九已至距潘,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間只搁,已是汗流浹背音比。 一陣腳步聲響...
    開封第一講書人閱讀 32,004評論 1 266
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留须蜗,地道東北人硅确。 一個月前我還...
    沈念sama閱讀 46,401評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像明肮,于是被迫代替她去往敵國和親菱农。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,566評論 2 349

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

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理柿估,服務(wù)發(fā)現(xiàn)循未,斷路器,智...
    卡卡羅2017閱讀 134,633評論 18 139
  • spring支持編程式事務(wù)管理和聲明式事務(wù)管理兩種方式秫舌。 編程式事務(wù)管理使用TransactionTemplate...
    熊熊要更努力閱讀 245評論 0 0
  • 對大多數(shù)Java開發(fā)者來說的妖,Spring事務(wù)管理是Spring應(yīng)用中最常用的功能,使用也比較簡單足陨。本文主要從三個方...
    sherlockyb閱讀 3,203評論 0 18
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,773評論 6 342
  • 1 什么是事務(wù) 生活中關(guān)于事務(wù)有一個常見的場景嫂粟,即銀行用戶轉(zhuǎn)賬。簡單的講墨缘,轉(zhuǎn)賬可以分為下面 2 個步驟: 查看用戶...
    millions_chan閱讀 609評論 0 4