JavaWeb學習總結(十三)--數據庫連接池


一、數據庫連接池的概念

     用池來管理Connection,這可以重復使用Connection。有了池,所以我們就不用自己來創建Connection,而是通過池來獲取Connection對象。當使用完Connection后,調用Connection的close()方法也不會真的關閉Connection,而是把Connection“歸還”給池。池就可以再利用這個Connection對象了。

 

 

JDBC數據庫連接池接口(DataSource

 

  Java為數據庫連接池提供了公共的接口:javax.sql.DataSource,各個廠商可以讓自己的連接池實現這個接口。這樣應用程序可以方便的切換不同廠商的連接池!

 

開源數據庫連接池

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

  • DBCP 數據庫連接池
  • C3P0 數據庫連接池

  在使用了數據庫連接池之后,在項目的實際開發中就不需要編寫連接數據庫的代碼了,直接從數據源獲得數據庫的連接。

 

JDBC數據庫連接池接口(DataSource

  Java為數據庫連接池提供了公共的接口:javax.sql.DataSource,各個廠商可以讓自己的連接池實現這個接口。這樣應用程序可以方便的切換不同廠商的連接池!

 

 

二、DBCP

 

   DBCP是Apache提供的一款開源免費的數據庫連接池!Tomcat 的連接池正是采用該連接池來實現的。該數據庫連接池既可以與應用服務器整合使用,也可由應用程序獨立使用。Hibernate3.0之后不再對DBCP提供支持!因為Hibernate聲明DBCP有致命的缺欠!

需要應用程序應在系統中增加如下兩個 jar 文件:

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

實現DBCP

 1. 加入jar包

2.編寫dbcpconfig.properties

#連接設置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testdb
username=root
password=123456

#<!-- 初始化連接 -->
initialSize=10

#最大連接數量
maxActive=50

#<!-- 最大空閑連接 -->
maxIdle=20

#<!-- 最小空閑連接 -->
minIdle=5

#<!-- 超時等待時間以毫秒為單位 6000毫秒/1000等於60秒 -->
maxWait=60000


#JDBC驅動建立連接時附帶的連接屬性屬性的格式必須為這樣:[屬性名=property;] 
#注意:"user" 與 "password" 兩個屬性會被明確地傳遞,因此這里不需要包含他們。
connectionProperties=useUnicode=true;characterEncoding=UTF8

#指定由連接池所創建的連接的自動提交(auto-commit)狀態。
defaultAutoCommit=true

#driver default 指定由連接池所創建的連接的只讀(read-only)狀態。
#如果沒有設置該值,則“setReadOnly”方法將不被調用。(某些驅動並不支持只讀模式,如:Informix)
defaultReadOnly=false

#driver default 指定由連接池所創建的連接的事務級別(TransactionIsolation)。
#可用值為下列之一:NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=REPEATABLE_READ

 如下圖所示:

3、在獲取數據庫連接的工具類(如jdbcUtils)的靜態代碼塊中創建池

 

package cn.zy.utils;

import java.io.InputStream;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Properties;
import javax.sql.DataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;


/*
 * 數據庫連接工具類DBCP
 */
public class JdbcUtils_DBCP {
    /*
     * 在java中,編寫數據庫連接池需實現java.sql.DataSource接口,每一種數據庫連接池都是DataSource接口的實現
     * DBCP連接池就是javax.sql.DataSource接口的一個具體實現
     */
    private static DataSource ds =null;
    //在靜態代碼塊中創建數據庫連接池
    static {
        try {
            //加載配置文件
            InputStream in = JdbcUtils_DBCP.class.getClassLoader().getResourceAsStream("dbcpconfig.properties");
            Properties prop = new Properties();
            prop.load(in);
            //創建數據源
             ds = BasicDataSourceFactory.createDataSource(prop);
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    
    /*
     * 從數據源中獲取數據庫連接
     */
    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }
    
/* * 釋放資源 */ public static void release(Connection conn,Statement st,ResultSet rs){ if(rs!=null){ try{ rs.close(); }catch (Exception e){ e.printStackTrace(); } if(st!=null){ try { st.close(); } catch (Exception e) { e.printStackTrace(); } if(conn!=null){ try { conn.close(); } catch (SQLException e) { e.printStackTrace(); } } } } } }

測試連接

package cn.zy.test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.Test;

import cn.zy.utils.JdbcUtils_DBCP;

/*
 * 測試DBCP數據源
 */
public class DbcpTest {
    @Test
    public void dbcpDataSourceTest(){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            //獲取數據庫連接
            conn = JdbcUtils_DBCP.getConnection();
            String sql = "insert into account(name,money) values(?,?)";
            st = conn.prepareStatement(sql);
            st.setString(1, "D");
            st.setFloat(2, 2000);
            st.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
             //釋放資源
           JdbcUtils_DBCP.release(conn, st, rs);
        }
    }

}

 

三、C3P0數據源

C3P0是一個開源的JDBC連接池,它實現了數據源和JNDI綁定,支持JDBC3規范和JDBC2的標准擴展。目前使用它的開源項目有Hibernate,Spring等。C3P0數據源在項目開發中使用得比較多。

  c3p0與dbcp區別
  1. dbcp沒有自動回收空閑連接的功能
  2. c3p0有自動回收空閑連接功能

在應用程序中加入C3P0連接池

1.導入相關jar包

c3p0-0.9.2-pre1.jar、mchange-commons-0.2.jar,如果操作的是Oracle數據庫,那么還需要導入c3p0-oracle-thin-extras-0.9.2-pre1.jar

2、在src下加入C3P0的配置文件:c3p0-config.xml,注意:

配置文件要求:

l  文件名稱:必須叫c3p0-config.xml

l  文件位置:必須在src下

   c3p0-config.xml的配置信息如下:

<?xml version="1.0" encoding="UTF-8"?>
<!--
c3p0-config.xml必須位於類路徑下面
private static ComboPooledDataSource ds;
static{
    try {
        ds = new ComboPooledDataSource("MySQL");
    } catch (Exception e) {
        throw new ExceptionInInitializerError(e);
    }
}
-->

<c3p0-config>
    <!--
    C3P0的缺省(默認)配置,
    如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource();”這樣寫就表示使用的是C3P0的缺省(默認)配置信息來創建數據源
    -->
    <default-config>
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </default-config>

    <!--
    C3P0的命名配置,
    如果在代碼中“ComboPooledDataSource ds = new ComboPooledDataSource("MySQL");”這樣寫就表示使用的是name是MySQL的配置信息來創建數據源
    -->
    <named-config name="MySQL">
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb</property>
        <property name="user">root</property>
        <property name="password">123456</property>
        
        <property name="acquireIncrement">5</property>
        <property name="initialPoolSize">10</property>
        <property name="minPoolSize">5</property>
        <property name="maxPoolSize">20</property>
    </named-config>

</c3p0-config>

如圖:

3、在獲取數據庫連接的工具類(如jdbcUtils)的靜態代碼塊中創建池

 1 package cn.zy.utils;
 2 
 3 import java.sql.Connection;
 4 import java.sql.ResultSet;
 5 import java.sql.SQLException;
 6 import java.sql.Statement;
 7
 8 import javax.sql.DataSource;
 9 
10 
11 import com.mchange.v2.c3p0.ComboPooledDataSource;
12 
13 /*
14  * 數據庫連接工具類
15  */
16 public class JdbcUtils_C3P0 {
17     private static ComboPooledDataSource dataSource = null;
18     //在靜態塊中創建數據庫連接池
19     static{
20         try {
21             //通過代碼創建數據庫連接池
22             /*ds = new ComboPooledDataSource();
23             ds.setDriverClass("com.mysql.jdbc.Driver");
24             ds.setJdbcUrl("jdbc:mysql://localhost:3306/testdb");
25             ds.setUser("root");
26             ds.setPassword("123456");
27             ds.setInitialPoolSize(10);
28             ds.setMinPoolSize(5);
29             ds.setMinPoolSize(20);*/
30             
31             //通過讀取xml來獲取數據源
32             //ds = new ComboPooledDataSource();//使用C3P0的默認配置來創建數據源
33             dataSource = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置來創建數據源    
34         } catch (Exception e) {
35             throw new ExceptionInInitializerError(e);
36         }
37     }
38     
39     /*
40      * 從數據源中獲取數據庫連接
41      */
42     public static Connection getConnection() throws SQLException {
43         return dataSource.getConnection();
44     }
45     
46     /*
47      * 返回連接池
48      */
49     public static DataSource getDataSource() {
50         return dataSource;
51     }
52     /*
53      * 釋放資源
54      */
55     public static void release(Connection conn,Statement st,ResultSet rs){
56         if(rs!=null){
57             try{
58                 //關閉存儲查詢結果的ResultSet對象
59                 rs.close();
60             }catch (Exception e) {
61                 e.printStackTrace();
62             }
63             rs = null;
64         }
65         if(st!=null){
66             try{
67                 //關閉負責執行SQL命令的Statement對象
68                 st.close();
69             }catch (Exception e) {
70                 e.printStackTrace();
71             }
72         }
73         
74         if(conn!=null){
75             try{
76                 //將Connection連接對象還給數據庫連接池
77                 conn.close();
78             }catch (Exception e) {
79                 e.printStackTrace();
80             }
81         }
82     }
83 }
84         

 

編寫測試類:

package cn.zy.test;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import org.junit.Test;

import cn.zy.utils.JdbcUtils_C3P0;

public class C3p0Test {
    @Test
    public void fun(){
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            conn = JdbcUtils_C3P0.getConnection();
            String sql = "insert into account(name,money) values(?,?)";
            st = conn.prepareStatement(sql);
            st.setString(1, "F");
            st.setFloat(2,3000);
            st.executeUpdate();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

 

四、配置Tomcat數據源

     在實際開發中,我們有時候還會使用服務器提供給我們的數據庫連接池,比如我們希望Tomcat服務器在啟動的時候可以幫我們創建一個數據庫連接池,那么我們在應用程序中就不需要手動去創建數據庫連接池,直接使用Tomcat服務器創建好的數據庫連接池即可。要想讓Tomcat服務器在啟動的時候幫我們創建一個數據庫連接池,那么需要簡單配置一下Tomcat服務器。

4.1 Tomcat配置JNDI資源

JNDI(Java Naming and Directory Interface),Java命名和目錄接口,它對應於J2SE中的javax.naming包,
  這 套API的主要作用在於:它可以把Java對象放在一個容器中(JNDI容器),並為容器中的java對象取一個名稱,以后程序想獲得Java對象,只需 通過名稱檢索即可。其核心API為Context,它代表JNDI容器,其lookup方法為檢索容器中對應名稱的對象。

Tomcat服務器創建的數據源是以JNDI資源的形式發布的,所以說在Tomat服務器中配置一個數據源實際上就是在配置一個JNDI資源,通過查看Tomcat文檔,我們知道使用如下的方式配置tomcat服務器的數據源:

<Context>
  <Resource name="jdbc/datasource" auth="Container"
            type="javax.sql.DataSource" username="root" password="123456"
            driverClassName="com.mysql.jdbc.Driver" 
            url="jdbc:mysql://localhost:3306/testdb"
            maxActive="8" maxIdle="4"/>
</Context>

服務器創建好數據源之后,我們的應用程序又該怎么樣得到這個數據源呢,Tomcat服務器創建好數據源之后是以JNDI的形式綁定到一個JNDI容器中的,我們可以把JNDI想象成一個大大的容器,我們可以往這個容器中存放一些對象,一些資源,JNDI容器中存放的對象和資源都會有一個獨一無二的名稱,應用程序想從JNDI容器中獲取資源時,只需要告訴JNDI容器要獲取的資源的名稱,JNDI根據名稱去找到對應的資源后返回給應用程序。我們平時做javaEE開發時,服務器會為我們的應用程序創建很多資源,比如request對象,response對象,服務器創建的這些資源有兩種方式提供給我們的應用程序使用:第一種是通過方法參數的形式傳遞進來,比如我們在Servlet中寫的doPost和doGet方法中使用到的request對象和response對象就是服務器以參數的形式傳遞給我們的。第二種就是JNDI的方式,服務器把創建好的資源綁定到JNDI容器中去,應用程序想要使用資源時,就直接從JNDI容器中獲取相應的資源即可。

  對於上面的name="jdbc/datasource"數據源資源,在應用程序中可以用如下的代碼去獲取

1 Context initCtx = new InitialContext();
2 Context envCtx = (Context) initCtx.lookup("java:comp/env");
3 dataSource = (DataSource)envCtx.lookup("jdbc/datasource");

此種配置下,數據庫的驅動jar文件需放置在tomcat的lib下

4.2、配置Tomcat數據源

1、在Web項目的WebRoot目錄下的META-INF目錄創建一個context.xml文件

 

2、在Web項目的WebRoot目錄下的META-INF目錄創建一個context.xml文件

<?xml version="1.0" encoding="UTF-8"?>
<Context>
   <Resource 
       name="jdbc/datasource" 
       auth="Container"
       type="javax.sql.DataSource" 
       username="root" 
       password="123456"
       driverClassName="com.mysql.jdbc.Driver" 
       url="jdbc:mysql://localhost:3306/testdb"
       maxActive="8" 
       maxIdle="4"/>
</Context>

 

3、將數據庫的驅動jar文件需放置在tomcat的lib下

 

4、在獲取數據庫連接的工具類(如jdbcUtils)的靜態代碼塊中獲取JNDI容器中的數據源

 

 

package cn.zy.utils;

import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;

import javax.naming.Context;
import javax.naming.InitialContext;
import javax.sql.DataSource;

public class JdbcUtils_JNDI {
    private static DataSource ds = null;
    //在靜態代碼塊中創建數據庫連接池
    static{
        try {
            //初始化JNDI
            Context initCtx = new InitialContext();
            //得到JNDI容器
             Context envCtx = (Context) initCtx.lookup("java:comp/env");
            //從JNDI容器中檢索name為jdbc/datasource的數據源
             ds = (DataSource)envCtx.lookup("jdbc/datasource");
        } catch (Exception e) {
            throw new ExceptionInInitializerError(e);
        }
    }
    
    /*
     * 從數據源中獲取連接
     */
    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }
    
    /*
     * 釋放資源
     */
    public static void release(Connection conn,Statement st,ResultSet rs){
        if(rs!=null){
            try{
                rs.close();
            }catch (Exception e){
                e.printStackTrace();
            }
            if(st!=null){
                try {
                    st.close();
                } catch (Exception e) {
                    e.printStackTrace();
                }
                if(conn!=null){
                    try {
                        conn.close();
                    } catch (SQLException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
}

寫一個Servlet進行測試:

package cn.zy.test;

import java.io.IOException;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import cn.zy.utils.JdbcUtils_JNDI;

public class JNDITest extends HttpServlet {

    
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        Connection conn = null;
        PreparedStatement st = null;
        ResultSet rs = null;
        try {
            //獲取連接
            conn = JdbcUtils_JNDI.getConnection();
            String sql = "insert into account(name,money) values(?,?)";
            st = conn.prepareStatement(sql);
            st.setString(1, "F");
            st.setFloat(2, 2000);
            st.executeUpdate();
            response.getWriter().print("插入成功");
        } catch (Exception e) {
            e.printStackTrace();
        }finally{
            JdbcUtils_JNDI.release(conn, st, rs);
        }
    
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        doGet(request, response);
    }

}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM