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

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

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

    空間站

    北極心空

      BlogJava :: 首頁(yè) :: 聯(lián)系 :: 聚合  :: 管理
      15 Posts :: 393 Stories :: 160 Comments :: 0 Trackbacks
    ??????????????????????????????????????????? 事務(wù)管理最佳實(shí)踐全面解析
    ?
    前言
    寫(xiě)作這篇文章的起因,是前一段時(shí)間,我使用Jbpm工作流引擎開(kāi)發(fā)工作流管理系統(tǒng)的過(guò)程中,使用編程方式管理事務(wù)時(shí)遇到的問(wèn)題。
    由于之前很長(zhǎng)一段時(shí)間,我一直都在使用Spring和EJB容器的聲明式事務(wù)管理,因此,咋一遇到Jbpm這樣的編程方式管理事務(wù)的情況,一下子搞不定了!經(jīng)過(guò)幾天的研究,我重新思考了怎樣進(jìn)行事務(wù)管理這個(gè)問(wèn)題,并且發(fā)明了一種非常好的編程范式,或者說(shuō)是事務(wù)管理的最佳實(shí)踐。不敢獨(dú)享,拿出來(lái)與諸君共賞。請(qǐng)大家批評(píng)指正。
    前幾個(gè)月,我對(duì)C++和Java編程方式進(jìn)行了比較和研究。并且總結(jié)了一些C++編程中管理對(duì)象的最佳實(shí)踐。
    但由于那一段時(shí)間工作較忙,沒(méi)有及時(shí)把文章寫(xiě)出來(lái)。后來(lái)想寫(xiě)文章時(shí),卻找不到當(dāng)初為了說(shuō)明寫(xiě)的Java和C++演示代碼了。因此,該文一直未成,頗為遺憾!因此,這篇事務(wù)管理的文章,我不敢拖得太久。由于時(shí)間倉(cāng)促,寫(xiě)得不好,請(qǐng)大家見(jiàn)諒!
    ?
    事務(wù)管理
    企業(yè)級(jí)應(yīng)用,或者叫“信息管理系統(tǒng)”。這類(lèi)軟件通過(guò)數(shù)據(jù)庫(kù)持久化保存、處理的信息。它們工作的核心,就是數(shù)據(jù)庫(kù)。這類(lèi)應(yīng)用,是目前市場(chǎng)上最主流的商業(yè)應(yīng)用。
    事務(wù)管理,這個(gè)概念出自于數(shù)據(jù)庫(kù)管理系統(tǒng)中。事務(wù)是一個(gè)單元的工作,要么全做,要么全不做。
    事務(wù)管理對(duì)于維持?jǐn)?shù)據(jù)庫(kù)系統(tǒng)內(nèi)部保存的數(shù)據(jù)邏輯上的一致性、完整性,起著至關(guān)重要的作用。如:一個(gè)銀行應(yīng)用軟件中,轉(zhuǎn)帳的操作中,需要先在A用戶(hù)帳戶(hù)中減去資金,然后再在B用戶(hù)帳戶(hù)中增加相應(yīng)的資金。如果完成A帳戶(hù)操作后,由于系統(tǒng)故障或者網(wǎng)絡(luò)故障,沒(méi)有能夠完成接下來(lái)的操作,那么A帳戶(hù)中的資金就白白流失了。顯然,客戶(hù)是無(wú)法接受這樣的結(jié)果的!
    如果我們把一個(gè)A和B帳戶(hù)的操作放在一個(gè)事務(wù)單元中,那么如果遇到上述異常情況,A帳戶(hù)減少資金的操作會(huì)回滾。A帳戶(hù)的資金不會(huì)減少。
    ?
    事務(wù)管理和數(shù)據(jù)庫(kù)連接的關(guān)系
    事務(wù)管理的工作,需要在數(shù)據(jù)庫(kù)連接上進(jìn)行。如果沒(méi)有數(shù)據(jù)庫(kù)連接,事務(wù)管理是無(wú)法實(shí)施的。
    因此,一個(gè)事務(wù)單元,應(yīng)該小于或者等于一個(gè)數(shù)據(jù)庫(kù)連接的生命周期。
    ?
    事務(wù)管理最佳模式
    數(shù)據(jù)庫(kù)連接管理最佳模式
    數(shù)據(jù)庫(kù)連接,是一種很寶貴也很昂貴的資源。一個(gè)數(shù)據(jù)庫(kù)可以提供的數(shù)據(jù)庫(kù)連接總數(shù)是有限的。而且,獲取一次數(shù)據(jù)庫(kù)連接也是非常昂貴的操作。需要建立網(wǎng)絡(luò)連接。因此,我們應(yīng)當(dāng)盡可能的重用數(shù)據(jù)庫(kù)連接,讓數(shù)據(jù)庫(kù)連接維持的時(shí)間盡可能的長(zhǎng)。
    但是,我們也不能把數(shù)據(jù)庫(kù)連接維持的太久。因?yàn)椋衔囊呀?jīng)說(shuō)過(guò)了,一個(gè)數(shù)據(jù)庫(kù)可以提供的數(shù)據(jù)庫(kù)連接總數(shù)是有限的。如果數(shù)據(jù)庫(kù)連接的時(shí)間很長(zhǎng),那么其他需要數(shù)據(jù)庫(kù)連接的工作就無(wú)法得到所需的數(shù)據(jù)庫(kù)連接。
    因此,最佳的數(shù)據(jù)庫(kù)連接模式,是“每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接”這樣的使用模式。
    因?yàn)椋啻握?qǐng)求之間的時(shí)間間隔是無(wú)法預(yù)料的,可能長(zhǎng)達(dá)幾小時(shí)、甚至幾天。數(shù)據(jù)庫(kù)連接顯然不能白白的等待在那里。而應(yīng)該返回給數(shù)據(jù)庫(kù),或者數(shù)據(jù)庫(kù)連接緩沖池,讓其他程序和組件有機(jī)會(huì)使用數(shù)據(jù)庫(kù)連接。
    另外,如果一次數(shù)據(jù)庫(kù)連接,小于一次用戶(hù)請(qǐng)求,那么,數(shù)據(jù)庫(kù)連接的得到和關(guān)閉次數(shù)又太頻繁了。因?yàn)椋玫揭淮螖?shù)據(jù)庫(kù)連接是非常消耗資源的。一次用戶(hù)請(qǐng)求,是一個(gè)短時(shí)、瞬間的操作,完全沒(méi)有必要使用多個(gè)數(shù)據(jù)庫(kù)連接。
    另外,上文中說(shuō)過(guò),事務(wù)是依托在數(shù)據(jù)庫(kù)連接之上的。多個(gè)數(shù)據(jù)庫(kù)連接之間,是無(wú)法使用同一個(gè)事務(wù)的。(實(shí)際上,JTA分布式事務(wù)是可以在一個(gè)事務(wù)中使用多個(gè)數(shù)據(jù)庫(kù)連接的)
    因此,我們更應(yīng)該讓數(shù)據(jù)庫(kù)連接的生命周期盡可能的延長(zhǎng)。
    ?
    事務(wù)管理最佳模式
    最佳的數(shù)據(jù)庫(kù)連接模式,是“每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接”這樣的使用模式。事務(wù),與之相仿。最佳的事務(wù)管理模式,也是“每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接,一次事務(wù)”。
    一次用戶(hù)請(qǐng)求,是用戶(hù)對(duì)軟件系統(tǒng)功能的一次獨(dú)立調(diào)用。用戶(hù)當(dāng)然不希望他的一次操作,系統(tǒng)只執(zhí)行一部分這種情況的發(fā)生。因此,對(duì)一次用戶(hù)請(qǐng)求的響應(yīng),使用一次事務(wù),是非常和正確的。
    對(duì)于一次單純的查詢(xún)操作,不更改持久化數(shù)據(jù)庫(kù)中記錄,那么我們不需要使用事務(wù)。在數(shù)據(jù)庫(kù)操作發(fā)生錯(cuò)誤時(shí),拋出異常,讓用戶(hù)界面顯示出問(wèn)題即可。而對(duì)于更改數(shù)據(jù)庫(kù)記錄的操作,并且涉及到多次數(shù)據(jù)庫(kù)操作的,則必須使用事務(wù),以保證數(shù)據(jù)庫(kù)中記錄的完整性和真實(shí)性。
    ?
    數(shù)據(jù)庫(kù)連接和事務(wù)管理的反模式
    數(shù)據(jù)庫(kù)連接和事務(wù)管理,在應(yīng)用中有一些反模式。我們應(yīng)該避免這樣做,否則會(huì)死得很慘!
    一、數(shù)據(jù)庫(kù)連接和事務(wù)管理跨越一個(gè)客戶(hù)的多次請(qǐng)求
    這樣的數(shù)據(jù)庫(kù)連接和事務(wù),其持續(xù)時(shí)間是無(wú)法估量的。這樣嚴(yán)重影響軟件和數(shù)據(jù)庫(kù)的性能。這是絕對(duì)不可取的。
    二、每個(gè)數(shù)據(jù)庫(kù)操作,一次數(shù)據(jù)庫(kù)連接和事務(wù)
    這是一種非常常見(jiàn)的反模式。在采用DAO設(shè)計(jì)模式進(jìn)行O-R映射中,DAO接口的一個(gè)數(shù)據(jù)庫(kù)訪問(wèn)方法,就執(zhí)行一次數(shù)據(jù)庫(kù)連接的獲取和釋放,并且執(zhí)行一次或者多次事務(wù)。
    如,下面的代碼:
    /*
    ????4,刪除單條消息
    ????
    */
    ???publicvoid?deleteMessage(String?id){
    ???????Connection?conn
    =DB.getConnection();
    ???????Statement?stmt?
    =null;
    ???????ResultSet?rst
    =null;
    ??????
    try?{
    ???????stmt?
    =?conn.createStatement();
    ???????
    //拼裝SQL
    ???????String?sql="delete?from?message?where?id='"+id+"'";
    ??????stmt.executeUpdate(sql);
    ??????}
    ??????
    catch?(SQLException?ex)?{
    ????????ex.printStackTrace();
    ????????thrownew?DataAccessException();
    ??????}
    finally{
    ??????DB.freeDbResource(conn,stmt,rst);
    ??????}
    ?
    ???}


    這是典型的反模式。
    數(shù)據(jù)庫(kù)連接在Dao中得到和釋放。如果一次用戶(hù)請(qǐng)求需要用到多個(gè)Dao方法,那么就需要多次得到和釋放數(shù)據(jù)庫(kù)連接。造成了極大的浪費(fèi)。而且,也無(wú)法對(duì)多個(gè)Dao方法實(shí)施事務(wù)管理。
    另外,JDBC中,默認(rèn)的事務(wù)管理方式是自動(dòng)提交。上面的代碼只有一個(gè)SQL執(zhí)行語(yǔ)句。所有只有一次事務(wù)。如果Dao方法中有多個(gè)SQL語(yǔ)句,那么就會(huì)在一個(gè)Dao方法中使用多個(gè)事務(wù),多次提交到數(shù)據(jù)庫(kù)中,這也是極端錯(cuò)誤的!
    當(dāng)然,上面這個(gè)簡(jiǎn)單的Dao方法,并不會(huì)造成任何實(shí)際的損害,這里僅僅說(shuō)明這種使用方式是一種反模式。
    ?
    ?
    事務(wù)管理的最佳設(shè)計(jì)模式
    最佳的事務(wù)管理模式,是“每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接,一次事務(wù)”。那么,根據(jù)這個(gè)原則,具體我們應(yīng)該怎樣編寫(xiě)程序呢?
    一、事務(wù)管理的分層
    企業(yè)級(jí)應(yīng)用軟件中的代碼部分,可以分為以下幾個(gè)層次:
    ??? (一)控制器Controller層
    這是表現(xiàn)層的業(yè)務(wù)委派。它處理用戶(hù)的請(qǐng)求,完成用戶(hù)要求的功能。它接收用戶(hù)傳來(lái)的參數(shù),然后調(diào)用業(yè)務(wù)層的服務(wù)方法,完成所需的功能。
    根據(jù)“每次請(qǐng)求,一次數(shù)據(jù)庫(kù)連接,一次事務(wù)”的原則。似乎,這里是最好的得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)的地方。因?yàn)椋珻ontroller層中的每一個(gè)方法,對(duì)應(yīng)著用戶(hù)的一次請(qǐng)求。
    但是,我認(rèn)為,這里決不應(yīng)該“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”。因?yàn)椋紫龋刂破鲗樱鳛楸憩F(xiàn)層技術(shù)的一部分,它的作用,僅僅是委派操作給業(yè)務(wù)層的服務(wù)方法,應(yīng)該盡可能的小。不應(yīng)該包括這些代碼。
    其次,管理數(shù)據(jù)庫(kù)連接和事務(wù),這是業(yè)務(wù)層的邏輯,應(yīng)該在業(yè)務(wù)層處理,而不是在表現(xiàn)層處理。
    更實(shí)際一點(diǎn)來(lái)說(shuō),Struts這種技術(shù)中,我們一般不使用Spring來(lái)管理Struts的控制器Action類(lèi)。這樣,如果“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”放在Struts的控制器層—Action類(lèi)中,那么Spring自動(dòng)管理數(shù)據(jù)庫(kù)連接和事務(wù)的聲明式事務(wù)管理機(jī)制就無(wú)法使用了!(當(dāng)然,Struts的Action也可以配置成Spring管理。)
    因此,我們應(yīng)該堅(jiān)決地拒絕在控制器層中處理數(shù)據(jù)庫(kù)連接和事務(wù)的誘惑!
    (二)業(yè)務(wù)服務(wù)Service層
    業(yè)務(wù)服務(wù)層,是業(yè)務(wù)邏輯的實(shí)際存放地。它們提供的服務(wù)分為2種:
    1,為控制器層提供服務(wù),處理用戶(hù)請(qǐng)求。
    2,為其他類(lèi)(不僅僅是控制器層,可能是其他Service方法等)提供服務(wù)。
    傳統(tǒng)上,大家都不區(qū)分這兩類(lèi)服務(wù)方法。統(tǒng)稱(chēng)為Service。
    而在我的方法中,我把它們區(qū)分開(kāi)來(lái)。我把Service層的服務(wù)方法分為3類(lèi):
    1,直接為控制器層提供服務(wù),并且需要使用到數(shù)據(jù)庫(kù)操作,從而需要處理數(shù)據(jù)庫(kù)連接和事務(wù)的,我把它們成為T(mén)ransaction方法。用*Transaction后綴標(biāo)識(shí)。
    這樣的方法,我仍然把它們放在Service接口中。當(dāng)你需要實(shí)現(xiàn)這樣的方法時(shí),看到后綴,你就知道,你需要在這里調(diào)用Dao方法,并且“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”。
    如果你不在這里進(jìn)行“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”的操作,那么系統(tǒng)一定會(huì)出現(xiàn)數(shù)據(jù)庫(kù)訪問(wèn)故障!
    2,為其他類(lèi)(可以是控制器層,也可能是其他Service方法等)提供服務(wù),并且不需要訪問(wèn)數(shù)據(jù)庫(kù)的方法。我稱(chēng)它們?yōu)镾ervice方法。使用*Service后綴,或者不使用后綴來(lái)標(biāo)識(shí)它們。
    這樣的方法,你可以無(wú)所顧忌的使用,既可以在控制器層中調(diào)用,也可以在任何代碼中調(diào)用!
    3,需要使用到數(shù)據(jù)庫(kù)操作,并且不可以直接被控制器層調(diào)用的方法。我稱(chēng)它們?yōu)镈ao方法。使用*Dao后綴來(lái)標(biāo)識(shí)它們。
    它們不是Dao接口中的方法,而是Service業(yè)務(wù)邏輯接口中的方法。我稱(chēng)它們?yōu)镈ao方法,并不是說(shuō),它們是Dao接口的方法,而是表示它們是Service層中需要使用Dao接口操縱數(shù)據(jù)庫(kù)的服務(wù)方法。并且,它們本身不含有“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”的代碼。因此,所有需要調(diào)用它們的方法,需要注意了,“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”這些任務(wù)還沒(méi)有做。如果直接在控制器層調(diào)用它們,那么一定會(huì)出現(xiàn)數(shù)據(jù)庫(kù)和事務(wù)的錯(cuò)誤!
    (三)DAO數(shù)據(jù)訪問(wèn)層
    DAO數(shù)據(jù)訪問(wèn)模式,是目前在數(shù)據(jù)訪問(wèn)層中用得最多的模式。在DAO中,使用各類(lèi)數(shù)據(jù)庫(kù)訪問(wèn)技術(shù)(如,JDBC,iBatis,Hibernate等)操作數(shù)據(jù)庫(kù),實(shí)現(xiàn)O-R映射。
    其中的方法,大都滿(mǎn)足“需要使用到數(shù)據(jù)庫(kù)操作,并且不可以直接被控制器層調(diào)用的方法”這樣一種情況。我們可以使用*Dao后綴來(lái)標(biāo)識(shí)這些方法,也可以不使用后綴。因?yàn)镈ao接口的方法,大抵都是這類(lèi)方法。
    ?
    二、數(shù)據(jù)庫(kù)連接和事務(wù)管理最佳模式
    在我們的編程范式中,是這樣工作的:
    控制器層,接收用戶(hù)請(qǐng)求參數(shù),并委派給業(yè)務(wù)層的Service接口執(zhí)行業(yè)務(wù)邏輯。它可以直接調(diào)用Service接口的*Transaction方法和*Service方法或者沒(méi)有后綴的一般方法。
    其中,*Transaction方法需要用到數(shù)據(jù)庫(kù)。其中必然調(diào)用了業(yè)務(wù)層的Dao方法,或者DAO層的數(shù)據(jù)庫(kù)訪問(wèn)方法。其實(shí)現(xiàn)方法中必然有處理“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”的代碼。
    而*Service方法或者沒(méi)有后綴的一般方法,則沒(méi)有使用數(shù)據(jù)庫(kù)。
    在DAO數(shù)據(jù)訪問(wèn)層,執(zhí)行數(shù)據(jù)庫(kù)操作的DAO方法,并不需要?jiǎng)?chuàng)建和關(guān)閉數(shù)據(jù)庫(kù)連接,也不需要處理事務(wù)。它們之需要得到數(shù)據(jù)庫(kù)連接,然后使用這個(gè)連接即可。(數(shù)據(jù)庫(kù)連接,可以通過(guò)參數(shù)從外部得到,也可以從本地線程變量中得到。后者是目前主流的技術(shù))
    這就是我提出的“事務(wù)管理最佳實(shí)踐”的工作情況。
    在Service業(yè)務(wù)層和DAO數(shù)據(jù)訪問(wèn)層中,我們都使用了“接口—實(shí)現(xiàn)類(lèi)”相分離的設(shè)計(jì)模式。
    一、編程方式的數(shù)據(jù)庫(kù)連接和事務(wù)管理
    假設(shè),現(xiàn)在我們使用多種數(shù)據(jù)庫(kù)訪問(wèn)技術(shù),來(lái)進(jìn)行O-R映射。看看我們這個(gè)架構(gòu)的適應(yīng)能力。
    我們的系統(tǒng),分別使用JDBC,iBatis,Hibernate這三種數(shù)據(jù)庫(kù)訪問(wèn)技術(shù),使用編程方式手工管理數(shù)據(jù)庫(kù)連接和事務(wù),不使用Spring這樣的IOC容器進(jìn)行管理。看看我們需要做什么:
    (一)JDBC編程方式管理數(shù)據(jù)庫(kù)連接和事務(wù)
    首先,開(kāi)發(fā)一個(gè)JDBCUtil類(lèi),得到數(shù)據(jù)庫(kù)連接,并且把它們放在一個(gè)線程變量中,以便一個(gè)線程重用一個(gè)數(shù)據(jù)庫(kù)連接。
    然后,開(kāi)發(fā)DAO接口的實(shí)現(xiàn)類(lèi)。實(shí)現(xiàn)DAO方法。從本地線程變量中得到數(shù)據(jù)庫(kù)連接,使用它。不需要關(guān)閉這個(gè)連接,也不需要管理事務(wù)。
    接著,開(kāi)發(fā)Serivce層的*Dao后綴命名的方法。它們只需要調(diào)用DAO接口的方法即可。不需要和數(shù)據(jù)庫(kù)連接、事務(wù)打交道。
    最后,開(kāi)發(fā)Service層的*Transaction后綴命名的方法。它們調(diào)用JDBCUtil類(lèi)的方法,創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)連接,并把它放在JDBCUtil類(lèi)的本地線程變量中,設(shè)置conn.setAutoCommit(false);等待DAO接口的方法去取這個(gè)已經(jīng)設(shè)為不自動(dòng)提交的數(shù)據(jù)庫(kù)連接。
    然后,在Try塊中,調(diào)用Dao方法(Service接口或者DAO接口的Dao方法)。調(diào)用結(jié)束之后,提交事務(wù),并在異常處理模塊中,設(shè)置回滾。最后,在finally塊中關(guān)閉數(shù)據(jù)庫(kù)連接,清除本地線程變量的值。
    (二)iBatis編程方式管理數(shù)據(jù)庫(kù)連接和事務(wù)
    iBatis本身就是使用本地線程變量來(lái)管理數(shù)據(jù)庫(kù)連接的。
    1,DAO接口的實(shí)現(xiàn)方法中,調(diào)用iBatis代碼,執(zhí)行數(shù)據(jù)庫(kù)操作。
    2,Service層的Dao方法,不需要任何更改。
    3,Service層的Transaction方法,需要使用iBatis的事務(wù)管理代碼。

    private?SqlMapClient?sqlMap?=?XmlSqlMapBuilder.buildSqlMap(reader);?
    public?updateItemDescriptionTransaction?(String?itemId,?String?newDescription)?throws?SQLException?{?
    try?{?
    sqlMap.startTransaction?();?
    dao方法調(diào)用;
    sqlMap.commitTransaction?();?
    }?
    finally?{?
    sqlMap.endTransaction?();?
    }?
    }?

    iBatis處理事務(wù)的代碼,也處理得數(shù)據(jù)庫(kù)連接。并且,事務(wù)的回滾也被iBatis搞定了。
    也就是說(shuō),換了一種數(shù)據(jù)庫(kù)訪問(wèn)技術(shù),只需要改變Service層中*Transaction方法的實(shí)現(xiàn)和DAO層的實(shí)現(xiàn)。
    (三)Hibernate編程方式管理數(shù)據(jù)庫(kù)連接和事務(wù)
    Hibernate也是如此。
    下面是Hibernate的助手類(lèi):
    publicclass?HibernateSessionFactoryFromJbpm?{
    ????
    ????privatestaticfinal?ThreadLocal?threadLocal?
    =?new?ThreadLocal();
    ????privatestatic?org.hibernate.SessionFactory?sessionFactory;
    ????
    /**
    ?????*ReturnstheThreadLocalSessioninstance.?Lazyinitialize
    ?????*the<code>SessionFactory</code>ifneeded.
    ?????*
    ?????*?@returnSession
    ?????*?@throwsHibernateException
    ?????
    */
    ????publicstatic?Session?getSession()?
    throws?HibernateException?{
    ????????Session?session?
    =?(Session)?threadLocal.get();
    ?
    ???????
    if?(session?==?null?||?!session.isOpen())?{
    ???????????
    if?(sessionFactory?==?null)?{
    ??????????????rebuildSessionFactory();
    ???????????}
    ???????????session?
    =?(sessionFactory?!=?null)???sessionFactory.openSession()
    ??????????????????:?
    null;
    ???????????threadLocal.set(session);
    ???????}
    ?
    ????????
    return?session;
    ????}
    ????
    /**
    ?????*?Rebuildhibernatesessionfactory
    ?????*
    ?????
    */
    ????publicstaticvoid?rebuildSessionFactory()?{
    ???????
    try?{
    ???????
    //?configuration.configure(configFile);
    ???????????
    //sessionFactory?=?configuration.buildSessionFactory();
    ???????????sessionFactory?=HibernateHelper.createSessionFactory();
    ???????}?
    catch?(Exception?e)?{
    ???????????System.err
    ??????????????????.println(
    "%%%%?Error?Creating?SessionFactory?%%%%");
    ???????????e.printStackTrace();
    ???????}
    ????}
    ????
    /**
    ?????*?Closethesinglehibernatesessioninstance.
    ?????*
    ?????*?@throwsHibernateException
    ?????
    */
    ????publicstaticvoid?closeSession()?
    throws?HibernateException?{
    ????????Session?session?
    =?(Session)?threadLocal.get();
    ????????threadLocal.set(
    null);
    ?
    ????????
    if?(session?!=?null)?{
    ????????????session.close();
    ????????}
    ????}
    }
    Hibernate的Session,是對(duì)JDBC?Connection的封裝。Hibernate不同于JDBC和iBatis。它默認(rèn)就把自動(dòng)提交設(shè)為false。也就是說(shuō),如果你不顯式的使用Hiberante事務(wù),那么根本不會(huì)操作數(shù)據(jù)庫(kù)!這點(diǎn)需要注意。
    (四)Jbpm對(duì)Hiberante的封裝
    另外,再說(shuō)一下Jbpm對(duì)Hiberante所作的封裝。Jbpm使用的是Hiberante3的數(shù)據(jù)庫(kù)訪問(wèn)技術(shù)。但是,它對(duì)Hibernate進(jìn)行了封裝。
    使用Jbpm,事務(wù)管理更加簡(jiǎn)單。
    如:
    public?List?getAllCanSeenTaskInstancesTransaction?(PageModule?view,String?userId)?throws?Exception?{
    ???????JbpmContext?jbpmContext?
    =?JbpmConfiguration.getInstance().createJbpmContext();
    ????????
    try?{
    ???????returnthis.getAllCanSeenTaskInstances(view,?userId);
    ????????}
    finally{
    ????????jbpmContext.close();
    ????????}
    ????}

    當(dāng) jbpmContext.close();方法執(zhí)行時(shí),自動(dòng)提交事務(wù)。如果發(fā)生異常,自動(dòng)回滾。并且,最后會(huì)關(guān)閉Hiberante本地線程中的Session,并清空該線程變量。
    ?
    二、聲明方式的數(shù)據(jù)庫(kù)連接和事務(wù)管理
    Spring容器管理業(yè)務(wù)代碼和DAO數(shù)據(jù)訪問(wèn)代碼,是現(xiàn)在非常常用的一種方式。使用Spring時(shí),我們一般使用Spring聲明式事務(wù)來(lái)管理數(shù)據(jù)庫(kù)連接和事務(wù)。
    另外,還有EJB容器也有聲明式事務(wù)管理的機(jī)制,兩者的使用方法大體相同,我就不再論述,這里只說(shuō)Spring。
    Spring管理下的JDBC,iBatis,Hibernate數(shù)據(jù)庫(kù)訪問(wèn)方法。我們?cè)贒AO接口的實(shí)現(xiàn)類(lèi)中,可以使用Spring提供的助手類(lèi)的便利方法,進(jìn)行數(shù)據(jù)庫(kù)操作。也可以使用Spring提供的助手類(lèi),得到Connection,Session等進(jìn)行數(shù)據(jù)庫(kù)操作。或者使用Spring助手類(lèi)的execute()方法調(diào)用數(shù)據(jù)庫(kù)操作代碼。
    如果你原先使用自己的助手類(lèi)得到Connection,Session。那么你完全可以修改該助手類(lèi)的實(shí)現(xiàn)方法,改為從Spring得到Connection,Session。這樣就不需要修改DAO接口的實(shí)現(xiàn)類(lèi)!
    Service層中的Dao方法,仍然無(wú)需修改。
    對(duì)于Service層中的Transaction方法。我們需要去除“得到和關(guān)閉數(shù)據(jù)庫(kù)連接,管理事務(wù)”的代碼。然后,在Spring的配置文件中,對(duì)其應(yīng)用聲明式事務(wù)管理。運(yùn)行時(shí),Spring會(huì)通過(guò)SpringAOP技術(shù),自動(dòng)得到數(shù)據(jù)庫(kù)連接,管理事務(wù)。
    可見(jiàn),使用聲明式事務(wù)管理,我們只需要修改得到數(shù)據(jù)庫(kù)連接或者會(huì)話的Util助手類(lèi),以及Transaction方法即可。
    綜上所述,可以看到,我提出的這一套事務(wù)管理最佳實(shí)踐是一套非常靈活、強(qiáng)大、簡(jiǎn)潔的管理事務(wù)的最佳實(shí)踐。具有極其強(qiáng)大的適應(yīng)能力。采用這套編程范式,你可以很容易地徹底擺脫事務(wù)管理帶來(lái)的困擾!
    使用它,即使是編程方式管理事務(wù),也是非常簡(jiǎn)單而可愛(ài)的。
    ?
    ?
    ?
    ?
    ?
    ?

    Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1415958

    posted on 2006-12-02 17:07 蘆葦 閱讀(276) 評(píng)論(0)  編輯  收藏 所屬分類(lèi): Spring
    主站蜘蛛池模板: 97人伦色伦成人免费视频| 三年片在线观看免费| 精品韩国亚洲av无码不卡区| 亚洲国产视频久久| 亚洲人成www在线播放| 亚洲欧美第一成人网站7777| 亚洲欧美日韩中文无线码| 亚洲人片在线观看天堂无码| 亚洲国产精品成人AV在线| 亚洲av无码专区青青草原| 国产精品日本亚洲777| 男女啪啪免费体验区| 一本岛v免费不卡一二三区| 中文在线日本免费永久18近| 久久精品成人免费网站| 1a级毛片免费观看| 久久不见久久见免费影院| 国产国产人免费人成免费视频 | 特级毛片免费播放| 亚洲免费无码在线| 全免费a级毛片免费看| 亚洲视频在线免费看| 无码视频免费一区二三区 | 免费成人在线视频观看| 最近2019免费中文字幕6| 24小时免费直播在线观看| 日日操夜夜操免费视频| 国产中文在线亚洲精品官网| 亚洲AV无码乱码在线观看富二代 | 久久亚洲国产精品123区| 亚洲AV无码一区二区乱子伦| 亚洲性一级理论片在线观看| 亚洲人成网站999久久久综合| 一级特黄aaa大片免费看| 久久国产精品免费观看| 毛片免费在线播放| 国产综合精品久久亚洲| 亚洲国产综合精品| 日韩免费高清一级毛片| 久久国产乱子伦免费精品| 日本a级片免费看|