1. 程式人生 > >數據層優化-jdbc連接池簡述、druid簡介

數據層優化-jdbc連接池簡述、druid簡介

策略 帶來 方式 cte mysq ... 環境 立足 tomcat

終於回到既定軌道上了,這一篇講講數據庫連接池的相關知識,線程池以後有機會再結合項目單獨寫篇文章(自己給自己挖坑,不知道什麽時候能填上),從這一篇文章開始到本階段結束的文章都會圍繞數據庫和dao層的優化去寫,本篇是一個開始。本文會介紹連接池技術並對比目前比較流行的java連接池技術,之後,會把druid整合到項目中來,將技術方案落地,實際整合到項目中,讓技術能為我所用。

使用連接池的原因

jdbc的demo

//第一步,註冊驅動程序  
//com.MySQL.jdbc.Driver  
Class.forName("數據庫驅動的完整類名");
//第二步,獲取一個數據庫的連接  
Connection conn = DriverManager.getConnection("數據庫地址","用戶名","密碼");    
//第三步,創建一個會話  
Statement stmt=conn.createStatement();   
//第四步,執行SQL語句  
stmt.executeUpdate("SQL語句");  
//或者查詢記錄  
ResultSet rs = stmt.executeQuery("查詢記錄的SQL語句");  
//第五步,對查詢的結果進行處理  
while(rs.next()){  
//操作  
}  
//第六步,關閉連接  
rs.close();  
stmt.close();  
conn.close();

對上面幾行代碼,大家不會陌生,這可能是我們初學jdbc連接時最熟悉的代碼了,雖然現在可能用到了一些數據層ORM框架,但是底層實現依然如同上面代碼一樣,只是做了一些封裝而已。這種方式也有一些不足,在與mysql進行數據交互時每次都需要新建connection資源,用完後關閉掉Connection資源,這種做法是非常浪費資源的,如果擡杠的話,可能有人會說,我就喜歡這種方式,我服務器配置足夠好,我一點都不擔心什麽資源不資源,那你牛逼。

浪費資源這種說法是相對而言的,如果在小型項目中或者項目與數據庫的交互不那麽頻繁的話,數據庫連接的創建與關閉也不見得會把資源浪費多少,亦或者在項目啟動時期,我們可能只考慮功能實現,就直接copy一份現成的數據庫集成代碼過來用,這種做法都是很正常的現象,本階段的內容主要是項目優化,那麽關註點肯定就不是項目初始時期,也不去討論硬件配置有多好,而是針對目前代碼中的不足進行優化,找到一個相對較好的優化方案,並落實到項目中去,今天我們講的優化方案就是使用連接池技術代替目前與數據庫的交互方式。

為什麽在連接數據庫時要使用連接池?
數據庫連接是一種關鍵的有限的昂貴的資源,一個數據庫連接對象均對應一個物理數據庫連接,每次操作都打開一個物理連接,使用完都關閉連接,這樣造成系統的性能低下。

數據庫連接池的解決方案是在應用程序啟動時建立足夠的數據庫連接,並將這些連接組成一個連接池,簡單的說,就是在一個"池"裏放了好多半成品的數據庫連接對象,由應用程序動態地對池中的連接進行申請、使用和釋放等操作。

連接池技術盡可能多地重用了消耗內存地資源,大大節省了內存,提高了服務器的服務效率,減少了程序與數據庫交互時的部分開銷,顯著的改善應用程序的性能,通過使用連接池,提高了程序運行效率,同時,我們可以通過其自身的管理機制來監視數據庫連接的數量、使用情況等。

連接池的工作原理

連接池技術的核心思想是連接復用(也是我們在前一篇文章中提到的資源重用),通過建立一個數據庫連接池以及一套連接使用、分配和管理策略,使得該連接池中的連接可以得到高效、安全的復用,避免了數據庫連接頻繁建立、關閉的開銷。

連接池的工作原理主要由三部分組成,分別為連接池的建立、連接池中連接的使用管理、連接池的關閉:

  • 第一、連接池的建立。一般在系統初始化時,連接池會根據系統配置建立,並在池中創建了幾個連接對象,以便使用時能從連接池中獲取。連接池中的連接不能隨意創建和關閉,這樣避免了連接隨意建立和關閉造成的系統開銷。Java中提供了很多容器類可以方便的構建連接池,例如Vector、Stack等。

  • 第二、連接池的管理。連接池管理策略是連接池機制的核心,連接池內連接的分配和釋放對系統的性能有很大的影響。其管理策略是:

  • 當客戶請求數據庫連接時,首先查看連接池中是否有空閑連接,如果存在空閑連接,則將連接分配給客戶使用;
  • 如果沒有空閑連接,則查看當前所開的連接數是否已經達到最大連接數,如果沒達到就重新創建一個連接給請求的客戶;
  • 如果達到就按設定的最大等待時間進行等待,如果超出最大等待時間,則拋出異常給客戶。
  • 當客戶釋放數據庫連接時,先判斷該連接的引用次數是否超過了規定值,如果超過就從連接池中刪除該連接,否則保留為其他客戶服務。

    該策略保證了數據庫連接的有效復用,避免頻繁的建立、釋放連接所帶來的系統資源開銷。

  • 第三、連接池的關閉。當應用程序退出時,關閉連接池中所有的連接,釋放連接池相關的資源,該過程正好與創建相反。

連接池的優點及流行的連接池技術

對於連接池的優點,通過前文描述,我們也能得出以下結論:

  • 減少連接創建時間。連接池中的連接是已準備好的、可重復使用的,獲取後可以直接訪問數據庫,因此減少了連接創建的次數和時間。
  • 簡化的編程模式。當使用連接池時,每一個單獨的線程能夠像創建一個自己的JDBC連接一樣操作,允許用戶直接使用JDBC編程技術。
  • 控制資源的使用。如果不使用連接池,每次訪問數據庫都需要創建一個連接,這樣系統的穩定性受系統連接需求影響很大,很容易產生資源浪費和高負載異常。連接池能夠使性能最大化,將資源利用控制在一定的水平之下。連接池能控制池中的連接數量,增強了系統在大流量沖擊下的穩定性。

流行的Java連接池:

  • C3P0是一個開放源代碼的JDBC連接池,它在lib目錄中與Hibernate一起發布,包括了實現jdbc3和jdbc2擴展規範說明的Connection 和Statement 池的DataSources 對象。

  • DBCP (Database Connection Pool)是一個依賴Jakarta commons-pool對象池機制的數據庫連接池,Tomcat的數據源使用的就是DBCP。目前 DBCP 有兩個版本分別是 1.3 和 1.4。1.3 版本對應的是 JDK 1.4-1.5 和 JDBC 3,而1.4 版本對應 JDK 1.6 和 JDBC 4。因此在選擇版本的時候要看看你用的是什麽 JDK 版本了,功能上倒是沒有什麽區別。

  • Proxool是一個Java SQL Driver驅動程序,提供了對你選擇的其它類型的驅動程序的連接池封裝。可以非常簡單的移植到現存的代碼中。完全可配置。快速,成熟,健壯。可以透明地為你現存的JDBC驅動程序增加連接池功能

  • Druid是阿裏開源的一個數據庫連接池技術,號稱是目前最好的數據庫連接池,在功能、性能、擴展性方面,都超過其他數據庫連接池,包括DBCP、C3P0、BoneCP、Proxool、JBoss DataSource。Druid已經在阿裏巴巴部署了超過600個應用,經過一年多生產環境大規模部署的嚴苛考驗。

對比下來,最終選擇了Druid連接池,接下來也會將Druid技術整合到目前的項目中去,C3P0和DBCP都用過,也碰到一些問題,總體來說,功能中規中矩,比直接操作jdbc方式要好的多,但是對比與Druid的話就有些不足了,因為Druid是在目前市面上流行的連接池技術的基礎上開發出來的,你有的Druid有,你沒有的Druid也能提供,Druid不僅僅是一個高效可管理的數據庫連接池,它還有一套基於Filter-Chain模式的插件體系,也內置SQLParser功能,同時還能監控數據庫訪問性能,可以作為監控來使用,總結起來就是高效、功能強大、可擴展性好。

總結:目前的問題及解決方案

目前ssm-demo項目中與mysql服務器的交互使用的是Spring自帶的一個工具類,DriverManagerDataSource,配置文件如下:

<!-- 配置數據源 -->
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url"
                  value="jdbc:mysql://127.0.0.1:3306/ssm_db?useUnicode=true&amp;characterEncoding=UTF-8  "/>
       <property name="username" value="root"/>
        <property name="password" value="admin"/>
    </bean>

DriverManagerDataSource建立連接的作法是只要有連接就新建一個connection,根本沒有連接池的作用,也就是說文章前面所提到的資源消耗的弊端還是存在的,但是我們覺察不出來,感覺項目也挺正常的。這是因為目前網站的訪問量較小,與mysql數據庫的交互不頻繁,由於訪問量小,對後端的請求就少,因此mysql查詢就少,壓力也不會大,項目體量及訪問總量都很小,就更別提數據庫的QPS了,根本不值一提,也就是說現有的網站形勢下,根本不會對mysql數據庫產生任何的壓力,根本不會有死鎖的產生,根本不會有事務鎖的產生,根本不會有數據庫資源耗盡情況的產生,也根本不會有數據庫服務器崩掉的產生.....

但是如果網站的訪問量大了起來,功能豐富了起來,用戶訪問量增長了起來,是目前的10000倍、100000倍甚至更大的情況下,各種問題就隨之而來了,當然,這麽多問題出現了,我們是不是修改了數據連接池就好了?肯定不是,數據庫連接池僅僅解決了數據層的部分問題,對性能有一部分的提升,它不能解決掉網站演進過程中的各種問題,別想太多,因為過程中會出現各種各樣的問題,項目也會暴露出各個方面的不足,前端、後端、運維、DBA、架構....等等維度都有可能出現問題,需要不同的方案和不同的技術來優化,不要想著一勞永逸。

OK,可能有點扯遠了,還是說回到連接池,下一篇文章會介紹阿裏的Druid連接池技術並將其整合到項目中,待續。

數據層優化-jdbc連接池簡述、druid簡介