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);
        }
    
    }
  • 相关阅读:
    jsp教程
    域名解析配置
    ulimit调优|设置普通用户的ulimit值
    进程之间的通信方式
    javascript中的发布订阅模式与观察者模式
    浏览器提供的几种存储
    jquery库与其他库(比如prototype)冲突的解决方法
    流量削峰
    微服务架构下的安全认证与鉴权
    windows远程桌面无法拷贝文件的问题与解决方法
  • 原文地址:https://www.cnblogs.com/zydev/p/6114501.html
Copyright © 2011-2022 走看看