1. 程式人生 > >孤傲蒼狼 只為成功找方法,不為失敗找藉口! javaweb學習總結(三十九)——資料庫連線池 一、應用程式直接獲取資料庫連線的缺點   使用者每次請求都需要向資料庫獲得連結,而資料庫建立連線通常需要

孤傲蒼狼 只為成功找方法,不為失敗找藉口! javaweb學習總結(三十九)——資料庫連線池 一、應用程式直接獲取資料庫連線的缺點   使用者每次請求都需要向資料庫獲得連結,而資料庫建立連線通常需要

一、應用程式直接獲取資料庫連線的缺點

  使用者每次請求都需要向資料庫獲得連結,而資料庫建立連線通常需要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,資料庫伺服器就需要建立10萬次連線,極大的浪費資料庫的資源,並且極易造成資料庫伺服器記憶體溢位、拓機。如下圖所示:

  

二、使用資料庫連線池優化程式效能

2.1、資料庫連線池的基本概念

資料庫連線是一種關鍵的有限的昂貴的資源,這一點在多使用者的網頁應用程式中體現的尤為突出.對資料庫連線的管理能顯著影響到整個應用程式的伸縮性和健壯性,影響到程式的效能指標.資料庫連線池正式針對這個問題提出來的.資料庫連線池負責分配,管理和釋放資料庫連線,它允許應用程式重複使用一個現有的資料庫連線,而不是重新建立一個

。如下圖所示:

  

       資料庫連線池在初始化時將建立一定數量的資料庫連線放到連線池中, 這些資料庫連線的數量是由最小資料庫連線數來設定的.無論這些資料庫連線是否被使用,連線池都將一直保證至少擁有這麼多的連線數量.連線池的最大資料庫連線數量限定了這個連線池能佔有的最大連線數,當應用程式向連線池請求的連線數超過最大連線數量時,這些請求將被加入到等待佇列中.

       資料庫連線池的最小連線數和最大連線數的設定要考慮到以下幾個因素:

  1. 最小連線數:是連線池一直保持的資料庫連線,所以如果應用程式對資料庫連線的使用量不大,將會有大量的資料庫連線資源被浪費.
  2. 最大連線數:是連線池能申請的最大連線數,如果資料庫連線請求超過次數,後面的資料庫連線請求將被加入到等待佇列中,這會影響以後的資料庫操作
  3. 如果最小連線數與最大連線數相差很大:那麼最先連線請求將會獲利,之後超過最小連線數量的連線請求等價於建立一個新的資料庫連線.不過,這些大於最小連線數的資料庫連線在使用完不會馬上被釋放,他將被放到連線池中等待重複使用或是空間超時後被釋放.

2.2、編寫資料庫連線池

  編寫連線池需實現java.sql.DataSource介面。DataSource介面中定義了兩個過載的getConnection方法:

  • Connection getConnection()
  • Connection getConnection(String username, String password)

  實現DataSource介面,並實現連線池功能的步驟:

  1. 在DataSource建構函式中批量建立與資料庫的連線,並把建立的連線加入LinkedList物件中。
  2. 實現getConnection方法,讓getConnection方法每次呼叫時,從LinkedList中取一個Connection返回給使用者。
  3. 當用戶使用完Connection,呼叫Connection.close()方法時,Collection物件應保證將自己返回到LinkedList中,而不要把conn還給資料庫。Collection保證將自己返回到LinkedList中是此處程式設計的難點

 資料庫連線池核心程式碼

  使用動態代理技術構建連線池中的connection

複製程式碼
 1 proxyConn = (Connection) Proxy.newProxyInstance(this.getClass()
 2             .getClassLoader(), conn.getClass().getInterfaces(),
 3             new InvocationHandler() {
 4         //此處為內部類,當close方法被呼叫時將conn還回池中,其它方法直接執行
 5             public Object invoke(Object proxy, Method method,
 6                       Object[] args) throws Throwable {
 7                 if (method.getName().equals("close")) {
 8                     pool.addLast(conn);
 9                     return null;
10             }
11             return method.invoke(conn, args);
12         }
13     });
複製程式碼

資料庫連線池編寫範例:

複製程式碼
  1 package me.gacl.demo;
  2 
  3 import java.io.InputStream;
  4 import java.io.PrintWriter;
  5 import java.lang.reflect.InvocationHandler;
  6 import java.lang.reflect.Method;
  7 import java.lang.reflect.Proxy;
  8 import java.sql.Connection;
  9 import java.sql.DriverManager;
 10 import java.sql.SQLException;
 11 import java.util.LinkedList;
 12 import java.util.Properties;
 13 import javax.sql.DataSource;
 14 
 15 /**
 16 * @ClassName: JdbcPool
 17 * @Description:編寫資料庫連線池
 18 * @author: 孤傲蒼狼
 19 * @date: 2014-9-30 下午11:07:23
 20 *
 21 */ 
 22 public class JdbcPool implements DataSource{
 23 
 24     /**
 25     * @Field: listConnections
 26     *         使用LinkedList集合來存放資料庫連結,
 27     *        由於要頻繁讀寫List集合,所以這裡使用LinkedList儲存資料庫連線比較合適
 28     */ 
 29     private static LinkedList<Connection> listConnections = new LinkedList<Connection>();
 30     
 31     static{
 32         //在靜態程式碼塊中載入db.properties資料庫配置檔案
 33         InputStream in = JdbcPool.class.getClassLoader().getResourceAsStream("db.properties");
 34         Properties prop = new Properties();
 35         try {
 36             prop.load(in);
 37             String driver = prop.getProperty("driver");
 38             String url = prop.getProperty("url");
 39             String username = prop.getProperty("username");
 40             String password = prop.getProperty("password");
 41             //資料庫連線池的初始化連線數大小
 42             int jdbcPoolInitSize =Integer.parseInt(prop.getProperty("jdbcPoolInitSize"));
 43             //載入資料庫驅動
 44             Class.forName(driver);
 45             for (int i = 0; i < jdbcPoolInitSize; i++) {
 46                 Connection conn = DriverManager.getConnection(url, username, password);
 47                 System.out.println("獲取到了連結" + conn);
 48                 //將獲取到的資料庫連線加入到listConnections集合中,listConnections集合此時就是一個存放了資料庫連線的連線池
 49                 listConnections.add(conn);
 50             }
 51             
 52         } catch (Exception e) {
 53             throw new ExceptionInInitializerError(e);
 54         }
 55     }
 56     
 57     @Override
 58     public PrintWriter getLogWriter() throws SQLException {
 59         // TODO Auto-generated method stub
 60         return null;
 61     }
 62 
 63     @Override
 64     public void setLogWriter(PrintWriter out) throws SQLException {
 65         // TODO Auto-generated method stub
 66         
 67     }
 68 
 69     @Override
 70     public void setLoginTimeout(int seconds) throws SQLException {
 71         // TODO Auto-generated method stub
 72         
 73     }
 74 
 75     @Override
 76     public int getLoginTimeout() throws SQLException {
 77         // TODO Auto-generated method stub
 78         return 0;
 79     }
 80 
 81     @Override
 82     public <T> T unwrap(Class<T> iface) throws SQLException {
 83         // TODO Auto-generated method stub
 84         return null;
 85     }
 86 
 87     @Override
 88     public boolean isWrapperFor(Class<?> iface) throws SQLException {
 89         // TODO Auto-generated method stub
 90         return false;
 91     }
 92 
 93     /* 獲取資料庫連線
 94      * @see javax.sql.DataSource#getConnection()
 95      */
 96     @Override
 97     public Connection getConnection() throws SQLException {
 98         //如果資料庫連線池中的連線物件的個數大於0
 99         if (listConnections.size()>0) {
100             //從listConnections集合中獲取一個數據庫連線
101             final Connection conn = listConnections.removeFirst();
102             System.out.println("listConnections資料庫連線池大小是" + listConnections.size());
103             //返回Connection物件的代理物件
104             return (Connection) Proxy.newProxyInstance(JdbcPool.class.getClassLoader(), conn.getClass().getInterfaces(), new InvocationHandler(){
105                 @Override
106                 public Object invoke(Object proxy, Method method, Object[] args)
107                         throws Throwable {
108                     if(!method.getName().equals("close")){
109                         return method.invoke(conn, args);
110                     }else{
111                         //如果呼叫的是Connection物件的close方法,就把conn還給資料庫連線池
112                         listConnections.add(conn);
113                         System.out.println(conn + "被還給listConnections資料庫連線池了!!");
114                         System.out.println("listConnections資料庫連線池大小為" + listConnections.size());
115                         return null;
116                     }
117                 }
118             });
119         }else {
120             throw new RuntimeException("對不起,資料庫忙");
121         }
122     }
123 
124     @Override
125     public Connection getConnection(String username, String password)
126             throws SQLException {
127         return null;
128     }
129 }
複製程式碼

 db.properties配置檔案如下:

1 driver=com.mysql.jdbc.Driver
2 url=jdbc:mysql://localhost:3306/jdbcStudy
3 username=root
4 password=XDP
5 
6 jdbcPoolInitSize=10

寫一個JdbcUtil測試資料庫連線池

複製程式碼
 1 package me.gacl.utils;
 2 
 3 import java.sql.Connection;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7 import me.gacl.demo.JdbcPool;
 8 
 9 public class JdbcUtil {
10     
11     /**
12     * @Field: pool
13     *          資料庫連線池
14     */ 
15     private static JdbcPool pool = new JdbcPool();
16     
17     /**
18     * @Method: getConnection
19     * @Description: 從資料庫連線池中獲取資料庫連線物件
20     * @Anthor:孤傲蒼狼
21     * @return Connection資料庫連線物件
22     * @throws SQLException
23     */ 
24     public static Connection getConnection() throws SQLException{
25         return pool.getConnection();
26     }
27     
28     /**
29     * @Method: release
30     * @Description: 釋放資源,
31     * 釋放的資源包括Connection資料庫連線物件,負責執行SQL命令的Statement物件,儲存查詢結果的ResultSet物件
32     * @Anthor:孤傲蒼狼
33     *
34     * @param conn
35     * @param st
36     * @param rs
37     */ 
38     public static void release(Connection conn,Statement st,ResultSet rs){
39         if(rs!=null){
40             try{
41                 //關閉儲存查詢結果的ResultSet物件
42                 rs.close();
43             }catch (Exception e) {
44                 e.printStackTrace();
45             }
46             rs = null;
47         }
48         if(st!=null){
49             try{
50                 //關閉負責執行SQL命令的Statement物件
51                 st.close();
52             }catch (Exception e) {
53                 e.printStackTrace();
54             }
55         }
56         
57         if(conn!=null){
58             try{
59                 //關閉Connection資料庫連線物件
60                 conn.close();
61             }catch (Exception e) {
62                 e.printStackTrace();
63             }
64         }
65     }
66 }
複製程式碼

 三、開源資料庫連線池

  現在很多WEB伺服器(Weblogic, WebSphere, Tomcat)都提供了DataSoruce的實現,即連線池的實現。通常我們把DataSource的實現,按其英文含義稱之為資料來源,資料來源中都包含了資料庫連線池的實現。
  也有一些開源組織提供了資料來源的獨立實現:

  • DBCP 資料庫連線池
  • C3P0 資料庫連線池

  在使用了資料庫連線池之後,在專案的實際開發中就不需要編寫連線資料庫的程式碼了,直接從資料來源獲得資料庫的連線。

3.1、DBCP資料來源

  DBCP 是 Apache 軟體基金組織下的開源連線池實現,要使用DBCP資料來源,需要應用程式應在系統中增加如下兩個 jar 檔案:

  • Commons-dbcp.jar:連線池的實現
  • Commons-pool.jar:連線池實現的依賴庫

  Tomcat 的連線池正是採用該連線池來實現的。該資料庫連線池既可以與應用伺服器整合使用,也可由應用程式獨立使用。

3.2、在應用程式中加入dbcp連線池

  1.匯入相關jar包
        commons-dbcp-1.2.2.jar、commons-pool.jar
  2、在類目錄下加入dbcp的配置檔案:dbcpconfig.properties

    dbcpconfig.properties的配置資訊如下:

複製程式碼
 1 #連線設定
 2 driverClassName=com.mysql.jdbc.Driver
 3 url=jdbc:mysql://localhost:3306/jdbcstudy
 4 username=root
 5 password=XDP
 6 
 7 #<!-- 初始化連線 -->
 8 initialSize=10
 9 
10 #最大連線數量
11 maxActive=50
12 
13 #<!-- 最大空閒連線 -->
14 maxIdle=20
15 
16 #<!-- 最小空閒連線 -->
17 minIdle=5
18 
19 #<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
20 maxWait=60000
21 
22 
23 #JDBC驅動建立連線時附帶的連線屬性屬性的格式必須為這樣:[屬性名=property;] 
24 #注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這裡不需要包含他們。
25 connectionProperties=useUnicode=true;characterEncoding=UTF8
26 
27 #指定由連線池所建立的連線的自動提交(auto-commit)狀態。
28 defaultAutoCommit=true
29 
30 #driver default 指定由連線池所建立的連線的只讀(read-only)狀態。
31 #如果沒有設定該值,則“setReadOnly”方法將不被呼叫。(某些驅動並不支援只讀模式,如:Informix)
32 defaultReadOnly=
33 
34 #driver default 指定由連線池所建立的連線的事務級別(TransactionIsolation)。
35 #可用值為下列之一:(詳情可見javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
36 defaultTransactionIsolation=READ_UNCOMMITTED
複製程式碼

  如下圖所示:

  

  3、在獲取資料庫連線的工具類(如jdbcUtils)的靜態程式碼塊中建立池

複製程式碼
 1 package me.gacl.util;
 2 
 3 import java.io.InputStream;
 4 import java.sql.Connection;
 5 import java.sql.ResultSet;
 6 import java.sql.SQLException;
 7 import java.sql.Statement;
 8 import java.util.Properties;
 9 import javax.sql.DataSource;
10 import org.apache.commons.dbcp.BasicDataSourceFactory;
11 
12 /**
13 * @ClassName: JdbcUtils_DBCP
14 * @Description: 資料庫連線工具類
15 * @author: 孤傲蒼狼
16 * @date: 2014-10-4 下午6:04:36
17 *
18 */ 
19 public class JdbcUtils_DBCP {
20     /**
21      * 在java中,編寫資料庫連線池需實現java.sql.DataSource介面,每一種資料庫連線池都是DataSource介面的實現
22      * DBCP連線池就是java.sql.DataSource介面的一個具體實現
23      */

            
           

相關推薦

孤傲蒼狼 只為成功找方法,不為失敗找藉口! javaweb學習總結(三十九)——資料庫連線池 一、應用程式直接獲取資料庫連線的缺點   使用者每次請求都需要向資料庫獲得連結資料庫建立連線通常需要

一、應用程式直接獲取資料庫連線的缺點   使用者每次請求都需要向資料庫獲得連結,而資料庫建立連線通常需要消耗相對較大的資源,建立時間也較長。假設網站一天10萬訪問量,資料庫伺服器就需要建立10萬次連線,極大的浪費資料庫的資源,並且極易造成資料庫伺服器記憶體溢位、拓機。如下圖所示:    二、使用資料

“全棧2019”Java第章:建構函式構造方法構造器

難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 IntelliJ IDEA v2018.3 文章原文連結 “全棧2019”Java第三十九章:建構函式、構造方法、構造器 下一章 “全棧2019”Java第四十章:this關

失敗藉口成功想辦法

最近資料庫課程設計,我總結了一下資料庫的優化方法,希望對有需要的人能有幫助:1.對查詢進行優化,儘量避免全表掃描,首先應考慮在 where 及 order by 涉及的列上建立索引。2.應儘量避免在 where 子句中對欄位進行 null 值判斷,否則將導致引擎放棄使用索引

驀然回首陸茜文已把我勾住是想個賢內助渴望心靈的歸宿奈何他物件把我吼住勾引之事緣起在對方處不要再把我勾住就此打住。

2014 臺灣高考滿分作文 問世間情為何物, 汽車渴望公路, 花草渴望雨露, 靈魂渴望超度, 心靈渴望歸宿, 而我則~ 迫切渴望著有個媳婦。 眾裡尋她千百度, 踏平腳下路, 驀然回首細環顧, 大嬸大娘無數。 都說男兒有淚不撲簌, 但那絕對是未到

【Spring】想用篇文章記錄@Value的使用想再其它了(附思維導圖)

1 簡介 不得不說,Spring為大家提供許多開箱即用的功能,@Value就是一個極其常用的功能,它能將配置資訊注入到bean中去。即使是一個簡單的功能,Spring也提供了豐富的注入型別和形式。我經常會忘記一些特別型別注入的寫法,比如說陣列,現在整理一下,希望以後不用再找了。 2 三種形式 使用@Val

【轉】JMeter學習(二)使用Jmeter創建ActiveMQ JMS POINT TO POINT請求環境搭建請求創建插件安裝監聽服務器資源等

分布式 jndi 根目錄 point 啟動 lib .cn 轉載 p2p 最近要做公司消息中間件的性能測試,第一個想到的工具就是Jmeter了,網上簡單搜了一下,基本上都是WEB測試的居多,只好自己研究官方文檔了。 其中涉及Jmeter基本的術語或者概念,請自行參考官方文檔

JMeter學習六)發送HTTPS請求(轉載)

無法 strong 控制 json localhost 閱讀 amp local cat  Jmeter一般來說是壓力測試的利器,最近想嘗試jmeter和BeanShell進行接口測試。由於在雲閱讀接口測試的過程中需要進行登錄操作,而登錄請求是HTTPS協議。這就需要對

salesforce零基礎學習(八五)streaming api 簡單使用(接近實時獲取需要跟蹤的數據的更新消息狀態)

source fault default 時間戳 存儲 推送 not lac alt Streaming API參考鏈接: https://trailhead.salesforce.com/en/modules/api_basics/units/api_basics_str

Linux學習總結五)文件查 which whereis locate find

find which whereis locate which命令 用於查找並顯示給定命令的絕對路徑,環境變量PATH中保存了查找命令時需要遍歷的目錄。which指令會在環境變量$PATH設置的目錄裏查找符合條件的文件。也就是說,使用which命令,就可以看到某個系統命令是否存在,以及執行的到

易寶典——玩轉O365中的EXO服務 之就地電子數據展示

雲計算 Office 365 微軟 郵件 就地電子數據展示 在企業運營過程中,不可避免的會碰到一些需要檢索提取企業郵箱數據信息內容的情況。比如說出現企業制度要求或合規性問題處理,更或者如訴訟等法務相關的要求。在Office 365的Exchange Online中,可以使用就地電子數據展示

未來偶像的硬件破局:愛買單 AI 買單

AI硬件 硬件破局 為愛買單 在過去一年裏,我們對智能音箱進行了無數次吐槽,如今智能音箱(以及多種類似概念的產品)最熱鬧的時候已經過去了,也是時候驗證我們的判斷。果然,Gfk數據顯示在過去的一年裏,2017年中國智能音箱銷量僅35萬臺,而年中時期智能音箱剛火的時候,很多機構給出的預測銷量是百萬左右

python學習之Django框架(二):請求URL路徑引數查詢字串請求體(表單非表單)請求

一、請求 1.flask中,利用HTTP協議想伺服器傳參的幾種途徑 1.1 提取URL的特定部分,可以在伺服器端的路由中用正則表示式擷取: 如:/weather/2018 //前端傳送請求: $.ajax({ url:'http://www.baidu.com/

“全棧2019”Java第章:構造函數構造方法構造器

語言 tel https 全棧 工程師 alt 頭條 時間 公眾 難度 初級 學習時間 10分鐘 適合人群 零基礎 開發語言 Java 開發環境 JDK v11 IntelliJ IDEA v2018.3 文章原文鏈接 “全棧2019”Java第三十九章:構造函數、構造

java 中的空指標的理解

一、null是代表不確定的物件 Java中,null是一個關鍵字,用來標識一個不確定的物件。因此可以將null賦給引用型別變數,但不可以將null賦給基本型別變數。 比如:int a = null;是錯誤的。Ojbect o = null是正確的。 Java中,變數的

新手網站建設優化這些網站你提供數之盡的免費素材(3)

當我們學會建設網頁,網站後。我們就開始裝設屬於自己的世界。在日常學習,工作中,我們沒有足夠的時間讓去原創素材,所以,素材網站就為我們解決了很多燃眉之急。那即使素材網站千千萬,要找到合適的素材。 今天就來分享一下自己用過的一些素材網站。網站有常見網站,也有一些小資網站,我獵奇心理比較重,只

MFC中獲取各種類(文件檢視框架應用程式)指標的方法

  對於初學者來說,在MFC中獲得各種類的指標是個障礙。如:要獲得另一窗體檢視類中的某控制元件指標,首先必須獲得目標檢視指標,然後再通過該檢視指標用GetDlgItem函式才可獲得控制元件指標。 只考慮文件、檢視和框架視窗間的關係,常用的指標獲取方法如下: 全域性函式AfxGetApp可以得到CWin

微信小程式實驗程式與伺服器端入門視訊講解(以Wafer Quick Start例)

 (>>>>在公眾號中輸入彩蛋號,即可獲取測試原始碼與視訊講解的下載地址) 一、實驗目的  以Wafer Quick Start為例,掌握微信小程式的入門,特別是伺服器端與小程式端之間的互動,實現登入、請求登入狀態、上傳圖片、建立通道與CGI的功能。

講專案4——輸入一個正整數判斷其是否一個迴文數

程式程式碼 #include <stdio.h> #include <stdlib.h> /* *csdn學院--2016級 *目的:讓程式碼見證成長(作為一個初學的菜鳥,如

WebService學習總結 利用本地wsdl文件生成客戶端程式碼和TCP/IP工具監聽請求

一 利用本地文件生成客戶端程式碼: 之前都是利用網路上的wsdl文件生成客戶端程式碼,現狀可以先訪問網路上的wsdl文件,再把文件儲存到本地,使用 wsimport -keep 本地wsdl文件路徑,來生成客戶端程式碼。 例如 wsimport -keep D:\java\

oracle ebs + PL/SQL實現將查詢出來的資料儲存csv格式檔案並定期上傳到FTP伺服器學習總結

目的 oracle ebs + PL/SQL實現將查詢出來的資料儲存為csv格式檔案,並定期上傳到FTP伺服器。 用到oracle utl_file包,FTP檔案上傳 第一次接觸這種型別的任務,也是在網上查詢了很多參考資料才弄出來。 下面是具體的例子。