zoukankan      html  css  js  c++  java
  • 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);
        }
    
    }
  • 相关阅读:
    CodeForces Gym 100500A A. Poetry Challenge DFS
    CDOJ 486 Good Morning 傻逼题
    CDOJ 483 Data Structure Problem DFS
    CDOJ 482 Charitable Exchange bfs
    CDOJ 481 Apparent Magnitude 水题
    Codeforces Gym 100637G G. #TheDress 暴力
    Gym 100637F F. The Pool for Lucky Ones 暴力
    Codeforces Gym 100637B B. Lunch 找规律
    Codeforces Gym 100637A A. Nano alarm-clocks 前缀和
    TC SRM 663 div2 B AABB 逆推
  • 原文地址:https://www.cnblogs.com/zydev/p/6114501.html
Copyright © 2011-2022 走看看