<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    隨筆-28  評論-15  文章-81  trackbacks-0
     

    概述

    當(dāng)我們調(diào)用一個基于SpringService接口方法(如UserService#addUser())時,它將運行于Spring管理的事務(wù)環(huán)境中,Service接口方法可能會在內(nèi)部調(diào)用其它的Service接口方法以共同完成一個完整的業(yè)務(wù)操作,因此就會產(chǎn)生服務(wù)接口方法嵌套調(diào)用的情況,Spring通過事務(wù)傳播行為控制當(dāng)前的事務(wù)如何傳播到被嵌套調(diào)用的目標服務(wù)接口方法中。

    事務(wù)傳播是Spring進行事務(wù)管理的重要概念,其重要性怎么強調(diào)都不為過。但是事務(wù)傳播行為也是被誤解最多的地方,在本文里,我們將詳細分析不同事務(wù)傳播行為的表現(xiàn)形式,掌握它們之間的區(qū)別。

    事務(wù)傳播行為種類

    SpringTransactionDefinition接口中規(guī)定了7種類型的事務(wù)傳播行為,它們規(guī)定了事務(wù)方法和事務(wù)方法發(fā)生嵌套調(diào)用時事務(wù)如何進行傳播:

    1事務(wù)傳播行為類型

    事務(wù)傳播行為類型

    說明

    PROPAGATION_REQUIRED

    如果當(dāng)前沒有事務(wù),就新建一個事務(wù),如果已經(jīng)存在一個事務(wù)中,加入到這個事務(wù)中。這是最常見的選擇。

    PROPAGATION_SUPPORTS

    支持當(dāng)前事務(wù),如果當(dāng)前沒有事務(wù),就以非事務(wù)方式執(zhí)行。

    PROPAGATION_MANDATORY

    使用當(dāng)前的事務(wù),如果當(dāng)前沒有事務(wù),就拋出異常。

    PROPAGATION_REQUIRES_NEW

    新建事務(wù),如果當(dāng)前存在事務(wù),把當(dāng)前事務(wù)掛起。

    PROPAGATION_NOT_SUPPORTED

    以非事務(wù)方式執(zhí)行操作,如果當(dāng)前存在事務(wù),就把當(dāng)前事務(wù)掛起。

    PROPAGATION_NEVER

    以非事務(wù)方式執(zhí)行,如果當(dāng)前存在事務(wù),則拋出異常。

    PROPAGATION_NESTED

    如果當(dāng)前存在事務(wù),則在嵌套事務(wù)內(nèi)執(zhí)行。如果當(dāng)前沒有事務(wù),則執(zhí)行與PROPAGATION_REQUIRED類似的操作。

    當(dāng)使用PROPAGATION_NESTED時,底層的數(shù)據(jù)源必須基于JDBC 3.0,并且實現(xiàn)者需要支持保存點事務(wù)機制。

    幾種容易引起誤解的組合事務(wù)傳播行為

    當(dāng)服務(wù)接口方法分別使用表1中不同的事務(wù)傳播行為,且這些接口方法又發(fā)生相互調(diào)用的情況下,大部分組合都是一目了然,容易理解的。但是,也存在一些容易引起誤解的組合事務(wù)傳播方式。

    下面,我們通過兩個具體的服務(wù)接口的組合調(diào)用行為來破解這一難點。這兩個服務(wù)接口分別是UserServiceForumServiceUserSerice有一個addCredits()方法,ForumSerivce#addTopic()方法調(diào)用了UserSerice#addCredits()方法,發(fā)生關(guān)聯(lián)性服務(wù)方法的調(diào)用:

    public class ForumService {

    private UserService userService;

    public void addTopic(){調(diào)用其它服務(wù)接口的方法

    //add Topic…

    userService.addCredits();被關(guān)聯(lián)調(diào)用的業(yè)務(wù)方法

    }

    }

    嵌套調(diào)用的事務(wù)方法

    Spring事務(wù)傳播行為最常見的一個誤解是:當(dāng)服務(wù)接口方法發(fā)生嵌套調(diào)用時,被調(diào)用的服務(wù)方法只能聲明為PROPAGATION_NESTED。這種觀點犯了望文生義的錯誤,誤認為PROPAGATION_NESTED是專為方法嵌套準備的。這種誤解遺害不淺,執(zhí)有這種誤解的開發(fā)者錯誤地認為:應(yīng)盡量不讓Service類的業(yè)務(wù)方法發(fā)生相互的調(diào)用,Service類只能調(diào)用DAO層的DAO類,以避免產(chǎn)生嵌套事務(wù)。

    其實,這種顧慮是完全沒有必要的,PROPAGATION_REQUIRED已經(jīng)清楚地告訴我們:事務(wù)的方法會足夠聰明地判斷上下文是否已經(jīng)存在一個事務(wù)中,如果已經(jīng)存在,就加入到這個事務(wù)中,否則創(chuàng)建一個新的事務(wù)。

    依照上面的例子,假設(shè)我們將ForumService#addTopic()UserSerice#addCredits()方法的事務(wù)傳播行為都設(shè)置為PROPAGATION_REQUIRED,這兩個方法將運行于同一個事務(wù)中。

    為了清楚地說明這點,可以將Log4J的日志設(shè)置為DEBUG級別,以觀察Spring事務(wù)管理器內(nèi)部的運行情況。下面將兩個業(yè)務(wù)方法都設(shè)置為PROPAGATION_REQUIREDSpring所輸出的日志信息如下:

    Using transaction object

    [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@e3849c]

    ForumService#addTopic()新建一個事務(wù)

    Creating new transaction with name [com.baobaotao.service.ForumService.addTopic]: PROPAGATION_REQUIRED,ISOLATION_DEFAULT

    Acquired Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] for JDBC transaction

    Switching JDBC Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5] to manual commit

    Bound value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] to thread [main]

    Initializing transaction synchronization

    Getting transaction for [com.baobaotao.service.ForumService.addTopic]

    Retrieved value [org.springframework.jdbc.datasource.ConnectionHolder@ee1ede] for key [org.apache.commons.dbcp.BasicDataSource@4204] bound to thread [main]

    Using transaction object [org.springframework.jdbc.datasource.DataSourceTransactionManager$DataSourceTransactionObject@8b8a47]

    UserService#addCredits()簡單地加入到已存在的事務(wù)中(即處創(chuàng)建的事務(wù))

    Participating in existing transaction

    Getting transaction for [com.baobaotao.service.UserService.addCredits]

    Completing transaction for [com.baobaotao.service.UserService.addCredits]

    Completing transaction for [com.baobaotao.service.ForumService.addTopic]

    Triggering beforeCommit synchronization

    Triggering beforeCompletion synchronization

    Initiating transaction commit

    調(diào)用底層Connection#commit()方法提交事務(wù)

    Committing JDBC transaction on Connection [org.apache.commons.dbcp.PoolableConnection@dc41c5]

    Triggering afterCommit synchronization

    Triggering afterCompletion synchronization

    Clearing transaction synchronization

    嵌套事務(wù)

    ForumService#addTopic()設(shè)置為PROPAGATION_REQUIRED時,UserSerice#addCredits()設(shè)置為PROPAGATION_REQUIREDPROPAGATION_SUPPORTSPROPAGATION_MANDATORY時,運行的效果都是一致的(當(dāng)然,如果單獨調(diào)用addCredits()就另當(dāng)別論了)。

    當(dāng)addTopic()運行在一個事務(wù)下(如設(shè)置為PROPAGATION_REQUIRED),而addCredits()設(shè)置為PROPAGATION_NESTED時,如果底層數(shù)據(jù)源支持保存點,Spring將為內(nèi)部的addCredits()方法產(chǎn)生的一個內(nèi)嵌的事務(wù)。如果addCredits()對應(yīng)的內(nèi)嵌事務(wù)執(zhí)行失敗,事務(wù)將回滾到addCredits()方法執(zhí)行前的點,并不會將整個事務(wù)回滾。內(nèi)嵌事務(wù)是內(nèi)層事務(wù)的一部分,所以只有外層事務(wù)提交時,嵌套事務(wù)才能一并提交。

    嵌套事務(wù)不能夠提交,它必須通過外層事務(wù)來完成提交的動作,外層事務(wù)的回滾也會造成內(nèi)部事務(wù)的回滾。

    嵌套事務(wù)和新事務(wù)

    PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED也是容易混淆的兩個傳播行為。PROPAGATION_REQUIRES_NEW 啟動一個新的、和外層事務(wù)無關(guān)的內(nèi)部事務(wù)。該事務(wù)擁有自己的獨立隔離級別和鎖,不依賴于外部事務(wù),獨立地提交和回滾。當(dāng)內(nèi)部事務(wù)開始執(zhí)行時,外部事務(wù)將被掛起,內(nèi)務(wù)事務(wù)結(jié)束時,外部事務(wù)才繼續(xù)執(zhí)行。

    由此可見, PROPAGATION_REQUIRES_NEW PROPAGATION_NESTED 的最大區(qū)別在于:PROPAGATION_REQUIRES_NEW 將創(chuàng)建一個全新的事務(wù),它和外層事務(wù)沒有任何關(guān)系,而 PROPAGATION_NESTED 將創(chuàng)建一個依賴于外層事務(wù)的子事務(wù),當(dāng)外層事務(wù)提交或回滾時,子事務(wù)也會連帶提交和回滾。

    其它需要注意問題

    以下幾個問題值得注意:

    1) 當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_MANDATORY時,它就不能被非事務(wù)的業(yè)務(wù)方法調(diào)用。如將ForumService#addTopic()設(shè)置為PROPAGATION_MANDATORY,如果展現(xiàn)層的Action直接調(diào)用addTopic()方法,將引發(fā)一個異常。正確的情況是:addTopic()方法必須被另一個帶事務(wù)的業(yè)務(wù)方法調(diào)用(如ForumService#otherMethod())。所以PROPAGATION_MANDATORY的方法一般都是被其它業(yè)務(wù)方法間接調(diào)用的。

    2) 當(dāng)業(yè)務(wù)方法被設(shè)置為PROPAGATION_NEVER時,它將不能被擁有事務(wù)的其它業(yè)務(wù)方法調(diào)用。假設(shè)UserService#addCredits()設(shè)置為PROPAGATION_NEVER,當(dāng)ForumService# addTopic()擁有一個事務(wù)時,addCredits()方法將拋出異常。所以PROPAGATION_NEVER方法一般是被直接調(diào)用的。

    3)當(dāng)方法被設(shè)置為PROPAGATION_NOT_SUPPORTED時,外層業(yè)務(wù)方法的事務(wù)會被掛起,當(dāng)內(nèi)部方法運行完成后,外層方法的事務(wù)重新運行。如果外層方法沒有事務(wù),直接運行,不需要做任何其它的事。

    小結(jié)

    Spring聲明式事務(wù)管理的配置中,事務(wù)傳播行為是最容易被誤解的配置項,原因在于事務(wù)傳播行為名稱(如PROPAGATION_NESTED:嵌套式事務(wù))和代碼結(jié)構(gòu)的類似性上(業(yè)務(wù)類方法嵌套調(diào)用另一個業(yè)務(wù)類方法)。這種誤解在很多Spring開發(fā)者中廣泛存在,本文深入講解了Spring事務(wù)傳播行為對業(yè)務(wù)方法嵌套調(diào)用的真實影響,希望能幫助讀者化解對事務(wù)傳播行為的困惑。
    posted on 2007-10-23 21:26 譚明 閱讀(422) 評論(0)  編輯  收藏 所屬分類: Spring
    主站蜘蛛池模板: 国产四虎免费精品视频| mm1313亚洲精品无码又大又粗| 最新亚洲精品国偷自产在线| 免费一级e一片在线播放| yellow视频免费看| 亚洲精品国产成人中文| 日本高清免费网站| 在线观看免费播放av片| 在线亚洲高清揄拍自拍一品区| 精品国产人成亚洲区| 精品国产sm捆绑最大网免费站| 无套内谢孕妇毛片免费看看 | 国产电影午夜成年免费视频| 亚洲精品精华液一区二区| 亚洲精品成人片在线观看精品字幕| 久久久久久精品成人免费图片| 特级毛片全部免费播放a一级 | 久久久久久亚洲精品| 免费看的成人yellow视频| 不卡视频免费在线观看| 亚洲色大18成人网站WWW在线播放| 夜夜春亚洲嫩草影院| 国产精品无码免费播放| 好紧我太爽了视频免费国产| 亚洲AV无码一区二区三区电影| 亚洲va无码专区国产乱码| 免费无码成人AV片在线在线播放 | 国产精品国产自线拍免费软件| 久99久精品免费视频热77| 精品久久久久久久久亚洲偷窥女厕| 亚洲A∨无码一区二区三区| yy6080久久亚洲精品| 噜噜嘿在线视频免费观看| 亚洲午夜免费视频| 久久精品成人免费观看97| 亚洲AV色无码乱码在线观看| 亚洲蜜芽在线精品一区| 亚洲午夜久久久影院伊人| 亚洲狠狠爱综合影院婷婷| 成人午夜性A级毛片免费| a拍拍男女免费看全片|