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

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

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

    沉睡森林@漂在北京

    本處文章除注明“轉載”外均為原創,轉載請注明出處。

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      152 隨筆 :: 4 文章 :: 114 評論 :: 0 Trackbacks

    在基于JDBC的數據庫應用開發中,數據庫連接的管理是一個難點,因為它是決定該應用性能的一個重要因素。本文在對數據庫連接進行透徹分析的基礎上,提出并實現了一個高效的連接管理策略,使得開發高性能的數據庫應用變得相對容易。特別是,對于連接管理中的兩個難點:事務和多線程問題進行了深入的剖析,并給出了一個基于設計模式的解決方案

    介紹

    在使用Java語言進行和數據庫有關的的應用開發中,一般都使用JDBC來進行和數據庫的交互,其中有一個關鍵的概念就是Connection(連接),它在Java中是一個類,代表了一個通道。通過它,使用數據的應用就可以從數據庫訪問數據了。

    對于一個簡單的數據庫應用,由于對于數據庫的訪問不是很頻繁。這時可以簡單地在需要訪問數據庫時,就新創建一個連接,用完后就關閉它,這樣做也不會帶來什么明顯的性能上的開銷。但是對于一個復雜的數據庫應用,情況就完全不同了。頻繁的建立、關閉連接,會極大的減低系統的性能,因為對于連接的使用成了系統性能的瓶頸。

    本文給出的方法可以有效的解決這個問題。在本方法中提出了一個合理、有效的連接管理策略,避免了對于連接的隨意、無規則的使用。該策略的核心思想是:連接復用。通過建立一個數據庫連接池以及一套連接使用管理策略,使得一個數據庫連接可以得到高效、安全的復用,避免了數據庫連接頻繁建立、關閉的開銷。另外,由于對JDBC中的原始連接進行了封裝,從而方便了數據庫應用對于連接的使用(特別是對于事務處理),提高了開發效率,也正是因為這個封裝層的存在,隔離了應用的本身的處理邏輯和具體數據庫訪問邏輯,使應用本身的復用成為可能。

     

    問題產生

    我參與的項目是開發一個網管系統,不可避免的要和數據庫打交道。剛開始時,由于對于數據庫的訪問不是很頻繁,對于數據庫連接的使用就是簡單的需要時就建立,用完就關閉的策略,這很符合XPeXtreme Programming)的口號:"Do the Simplest Thing that Could Possibly Work"。確實,開始時工作的很好。隨著項目的進展,對于數據庫的訪問開始變的頻繁,問題就暴露出來了,原先的通過簡單地獲取和關閉數據庫連接的方法將很大的影響系統的性能,這種影響是由于數據庫資源管理器進程頻繁的創建和摧毀那些連接對象而引起的。

    此時,就有必要對數據庫訪問方法進行重構(refactoring),因為我們確實需要進行改進,來提高系統的性能。

     

     

    解決方案

    可以看出,問題的根源就是由于對于連接資源的低效管理造成的。對于共享資源,有一個很著名的設計模式:資源池。該模式正是為了解決資源頻繁分配、釋放所造成的問題的。把該模式應用到數據庫連接管理領域,就是建立一個數據庫連接池,提供一套高效的連接分配、使用策略,最終目標是實現連接的高效、安全的復用。

    3.1、建立連接池

    第一步,就是要建立一個靜態的連接池,所謂靜態是指,池中的連接是在系統初始化時就分配好的,并且不能夠隨意關閉的。Java中給我們提供很多容器類可以方便的用來構建連接池,如:VectorStack等。在系統初始化時,根據配置創建連接并放置在連接池中,以后所使用的連接都是從該連接池中獲取的,這樣就可以避免連接隨意建立、關閉造成的開銷(當然,我們沒有辦法避免JavaGarbage Collection帶來的開銷)。

    3.2、分配、釋放策略

    有了這個連接池,下面我們就可以提供一套自定義的分配、釋放策略。

    當客戶請求數據庫連接時,首先看連接池中是否有空閑連接,這里的空閑是指,目前沒有分配出去的連接。如果存在空閑連接則把連接分配給客戶,并作相應處理,具體處理策略,在關鍵議題中會詳述,主要的處理策略就是標記該連接為已分配。若連接池中沒有空閑連接,就在已經分配出去的連接中,尋找一個合適的連接給客戶(選擇策略會在關鍵議題中詳述),此時該連接在多個客戶間復用。

    當客戶釋放數據庫連接時,可以根據該連接是否被復用,進行不同的處理。如果連接沒有使用者,就放入到連接池中,而不是被關閉。

    可以看出正是這套策略保證了數據庫連接的有效復用。

    3.3、配置策略

    數據庫連接池中到底要放置多少個連接,連接耗盡后該如何處理呢?這時一個配置策略。一般的配置策略是,開始時,根據具體的應用需求,給出一個初始的連接池中連接的數目以及一個連接池可以擴張到的最大連接數目。本方案就是按照這種策略實現的。

     

    關鍵議題

    本節將對上述解決方案中的關鍵細節進行詳述,正是這些關鍵的策略保證了數據庫連接復用的高效和安全。

    4.1、引用記數

    3.2節中的分配、釋放策略對于有效復用連接非常重要,我們采用的方法也是采用了一個很有名的設計模式:Reference Counting(引用記數)。該模式在復用資源方面用的非常廣泛,我們把該方法運用到對于連接的分配釋放上。每一個數據庫連接,保留一個引用記數,用來記錄該連接的使用者的個數。具體的實現上,我們采用了兩極連接池,空閑池和使用池。空閑池中存放目前還沒有分配出去被使用的連接,一旦一個連接被分配出去,那么就會放入到使用池中,并且增加引用記數。

    這樣做有一個很大的好處,使得我們可以高效的使用連接,因為一旦空閑池中的連接被全部分配出去,我們就可以根據相應的策略從使用池中挑選出一個已經正在使用的連接用來復用,而不是隨意拿出一個連接去復用。策略可以根據需要去選擇,我們采用的策略比較簡單:復用引用記數最小的連接。Java的面向對象特性,使得我們可以靈活的選擇不同的策略(提供一個不同策略共用的抽象接口,各個具體的策略都實現這個接口,這樣對于策略的處理邏輯就和策略的實現邏輯分離)。

    4.2、事務處理

    前面談到的都是關于使用數據庫連接進行普通的數據庫訪問。對于事務處理,情況就變得比較復雜。因為事務本身要求原子性的保證,此時就要求對于數據庫的操作符合"All-All-Nothing"原則,即要么全部完成,要么什么都不做。如果簡單的采用上述的連接復用的策略,就會發生問題,因為沒有辦法控制屬于同一個事務的多個數據庫操作方法的動作,可能這些數據庫操作是在多個連接上進行的,并且這些連接可能被其他非事務方法復用。

    Connection本身具有提供了對于事務的支持,可以通過設置ConnectionAutoCommit屬性為false,顯式的調用commit或者rollback方法來實現。但是要安全、高效的進行Connection進行復用,就必須提供相應的事務支持機制。我們采用的方法是:采用顯式的事務支撐方法,每一個事務獨占一個連接。這種方法可以大大降低對于事務處理的復雜性(如果事務不獨占一條連接,那么要保證事務的原子性并且又不妨礙復用該連接的其他和該事務無關的操作,基本上不可能,除非Connection類是你開發的),并且又不會妨礙連接的復用,因為隸屬于該事務的所有數據庫操作都是通過這一個連接完成的,并且事務方法又復用了其他一些數據庫方法。

    在我們的連接管理服務提供了顯式的事務開始、結束(commit或者rollback)聲明,以及一個事務注冊表,用于登記事務發起者和事務使用的連接的對應關系,通過該表,使用事務的部分和我們的連接管理部分就隔離開,因為該表是在運行時根據實際的調用情況,動態生成的。事務使用的連接在該事務運行中不能被復用。

    當使用者需要使用事務方法時,首先調用連接管理服務提供的beginTrans方法,該方法主要處理流程如下(偽碼描述)

               public void beginTrans( ) {

                       

                    conn = getIdleConnectionFromPoll( );

                    userId = getUserId( );

                    registerTrans(userId, conn);

                       

    }

     

    在我們的實現中,用戶標識是通過使用者所在的線程來標識的。后面的所有對于數據庫的訪問都是通過查找該注冊表,使用已經分配的連接來完成的。當事務結束時,從注冊表中刪除相應表項。

    對于嵌套的事務如何處理呢?我們采用的方法仍為引用記數,不過這里的引用記數是指的"嵌套層次",具體的細節,不再贅述。

    4.3、封裝

    從上面的論述可以看出,普通的數據庫方法和事務方法對于連接的使用(分配、釋放)是不同的,為了便于使用,對外提供一致的操作接口,我們對連接進行了封裝:即普通連接和事務連接。在此,我們利用了Java中的強大的面向對象特性:多態。普通連接和事務連接均實現了一個DbConnection接口,對于接口中定義的方法,分別根據自己的特點作了不同的實現,這樣在對于連接的處理上就非常的一致了。

    4.4、并發問題

    為了是我們的連接管理服務有更大的通用性,就必須要考慮到多線程環境,即并發問題。在一個多線程的環境下,我們必須要保證連接管理自身數據的一致性和連接內部數據是一致性,還好Java提供對這方面的很好的支持(synchronized關鍵字),這樣我們就很容易使連接管理成為線程安全的。

     

     

     

    結論

    本文給出了一個基本的連接管理框架,在其中使用了一些廣泛使用的設計模式(資源池,引用記數等),使得高效、安全的復用數據庫連接成為可能。當然,還有一些問題沒有考慮到,比如:沒有實現對不同種類的數據庫的聯合管理;沒有提供定時檢測機制,查詢連接的狀態等。另外在連接管理的使用包裝上比起一些商用的系統還顯粗糙,但是底層的基理是一致的,所以通過本文相信對于這些商用的產品中的相關功能會有更好的理解。

     

    參考資料

    Thinking in JavaBruce Eckel

    Real-Time Design Patterns Bruce Powel Dougladd

     

     

    posted on 2009-03-06 15:16 王總兵 閱讀(118) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 女人18毛片免费观看| 亚洲中文字幕久久精品无码APP| jzzijzzij在线观看亚洲熟妇| 亚洲国产综合人成综合网站| 三年片在线观看免费| 亚洲情A成黄在线观看动漫软件 | 国产AV无码专区亚洲A∨毛片| 在线免费中文字幕| 成a人片亚洲日本久久| 亚洲AV永久无码精品水牛影视| 色妞WWW精品免费视频| 爽爽爽爽爽爽爽成人免费观看| 中文字幕 亚洲 有码 在线| 久久精品亚洲男人的天堂| 色se01短视频永久免费| 日本特黄特色AAA大片免费| 亚洲六月丁香六月婷婷色伊人| 亚洲视频在线一区二区| 九九九精品成人免费视频| 国产综合免费精品久久久| 亚洲爆乳少妇无码激情| 亚洲视频中文字幕| 亚洲中文字幕伊人久久无码| 国产福利在线观看免费第一福利| 91成人免费福利网站在线| 亚洲妇女无套内射精| 亚洲男女性高爱潮网站| 亚洲精品午夜国产VA久久成人| 免费黄色毛片视频| 亚洲免费在线观看视频| 国产精品网站在线观看免费传媒| 老外毛片免费视频播放| 亚洲高清中文字幕免费| 91大神亚洲影视在线| 亚洲中文字幕第一页在线 | 国产免费看插插插视频| **真实毛片免费观看| 女同免费毛片在线播放| 一级毛片免费播放男男| 精品亚洲成A人在线观看青青| 亚洲精品福利你懂|