Java中JDBC连接池的基本原理及实现方式

目录
  • 一、 应用程序直接建立数据库连接模型
  • 二、使用数据库连接池优化模型
    • 1、关于连接池中的连接数量的一些规定:
    • 2、编写数据库连接池
    • 创建数据库连接池:
    • 进一步封装一些相关数据库的类的方法
  • 三、两个开源的数据库连接池
    • 1、dbcp连接
      • (1)导入相关jar包
      • (2)在项目根目录增加配置文件dbcp.properties
      • (3)程序实现dbcp连接
    • 2、c3p0连接池
      • (1)导入相关的jar包
      • (2)在项目根目录下增加配置文件
      • (3)编写类文件,创建连接池
    • 3、dbcp和c3p0不同之处

一、 应用程序直接建立数据库连接模型

应用程序直接每次访问数据库时,都建立创建一个数据库的链接,这样每次建立这样的连接都需要耗费的资源,当同时有很多用户在使用应用程序时,可能会导致应用程序崩溃。

图为应用程序直接建立数据库连接模型

二、使用数据库连接池优化模型

数据库连接池的基本思路是,平时建立适量的数据库的连接,放在一个集合中,当有用户需要建立数据库连接的时候,直接到集合中取出一个数据库连接对象(Connection),这样不用再需要重新创建,这样会节省大量的资源,当用户不需要在对数据库进行访问了,那么就将数据库连接对象(Connection)重新放回到集合中,以便方便下次使用。

数据库连接池优化模型图

1、关于连接池中的连接数量的一些规定:

  • (1)最小连接数:是连接池一直保持的数据库连接,所以如果应用程序对数据库连接的使用量不大,将会有大量的数据库连接资源被浪费(适量).
  • (2)最大连接数:是连接池能申请的最大连接数,如果数据库连接请求超过次数,后面的数据库连接请求将被加入到等待队列中,这会影响以后的数据库操作。通常在使用完起始集合中的连接后,会再重新创建一些数据库连接对象,用来满足用户需求,但是这种新建并不是无限制的。
  • (3)当使用完的连接对象需要重新放回到集合中以备使用,但是超过最小连接数的连接在使用完不会马上被释放,他将被放到连接池中等待重复使用或是超时后最终被释放。

2、编写数据库连接池

简单思路为:创建一个类继承DataSource接口,在类中实现静态的加载出配置文档db.properties文档,并创建最小连接量的数据库连接对象(Connection),添加到Linkedlist(选择Linkedlist集合原因是便于增删)集合中。重写getConnection()函数,在getConnection()函数中实现数据库连接对象的获取。

db.properties文档

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8
username=root
password=tiger

jdbcConnectionInitSize=10

创建数据库连接池:

package JDBC;

import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.Properties;
import java.util.logging.Logger;

import javax.sql.DataSource;

public class JdbcConnectionsPool implements DataSource {

    /*
     * 使用静态块代码,初始化连接池,创建连接池的中最小链接数量连接,
     * 创建linkedlist集合,将这些连接放入集合中
     */
    //创建linkedlist集合
    private static LinkedList<Connection> linkedlist1=new LinkedList<Connection>();
    private static String driver;//
    private static String url;//
    private static String username;//数据库登陆名
    private static String password;//数据库的登陆密码
    private static int jdbcConnectionInitSize;//最小连接数量
    private static int max=1; //当前最大连接数量=max*jdbcConnectionInitSize
    static{
        //通过反射机制获取访问db.properties文件
        InputStream is=JdbcConnectionsPool.class.getResourceAsStream("/db.properties");
        Properties prop=new Properties();
        try {
            //加载db.properties文件
            prop.load(is);
            //获取db.properties文件中的数据库连接信息
            driver=prop.getProperty("driver");
            url=prop.getProperty("url");
            username=prop.getProperty("username");
            password=prop.getProperty("password");
            jdbcConnectionInitSize=Integer.parseInt(prop.getProperty("jdbcConnectionInitSize"));

            Class.forName("com.mysql.jdbc.Driver");

            //创建最小连接数个数据库连接对象以备使用
            for(int i=0;i<jdbcConnectionInitSize;i++){
                Connection conn=DriverManager.getConnection(url, username, password);
                 System.out.println("获取到了链接" + conn);
                //将创建好的数据库连接对象添加到Linkedlist集合中
                linkedlist1.add(conn);
            }

        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (SQLException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {
        // TODO Auto-generated method stub

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {
        // TODO Auto-generated method stub

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        // TODO Auto-generated method stub
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        // TODO Auto-generated method stub
        return false;
    }

    /*
     * 实现数据库连接的获取和新创建
     */
    @Override
    public Connection getConnection() throws SQLException {
         //如果集合中没有数据库连接对象了,且创建的数据库连接对象没有达到最大连接数量,可以再创建一组数据库连接对象以备使用
         if(linkedlist1.size()==0&&max<=5){
             try {
                Class.forName("com.mysql.jdbc.Driver");
            } catch (ClassNotFoundException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
             for(int i=0;i<jdbcConnectionInitSize;i++){
               Connection conn=DriverManager.getConnection(url, username, password);
               System.out.println("获取到了链接" + conn);
               //将创建好的数据库连接对象添加到Linkedlist集合中
               linkedlist1.add(conn);
                }
             max++;
            }
        if(linkedlist1.size()>0){
            //从linkedlist集合中取出一个数据库链接对象Connection使用
            Connection conn1=linkedlist1.removeFirst();
            System.out.println("linkedlist1数据库连接池大小是" + linkedlist1.size());
            /*返回一个Connection对象,并且设置Connection对象方法调用的限制,
            *当调用connection类对象的close()方法时会将Connection对象重新收集放入linkedlist集合中。
            */
            return (Connection) Proxy.newProxyInstance(conn1.getClass().getClassLoader(),//这里换成JdbcConnectionsPool.class.getClassLoader();也行
                 conn1.getClass().getInterfaces(), new InvocationHandler() {

                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        if(!method.getName().equalsIgnoreCase("close")){
                            return method.invoke(conn1, args);
                        }else{
                            linkedlist1.add(conn1);
                            System.out.println(conn1+"对象被释放,重新放回linkedlist集合中!");
                            System.out.println("此时Linkedlist集合中有"+linkedlist1.size()+"个数据库连接对象!");
                            return null;
                            }
                        }
                   });
        }else{
            System.out.println("连接数据库失败!");
        }
        return null;
    }

    @Override
    public Connection getConnection(String username, String password) throws SQLException {

        return null;
    }

}

进一步封装一些相关数据库的类的方法

package JDBC;

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

public class JdbcConnectionPoolTest {

        /**
        * @Field: pool
        *          数据库连接池
        */
        private static JdbcConnectionsPool pool = new JdbcConnectionsPool();

        /**
        * @Method: getConnection
        * @Description: 从数据库连接池中获取数据库连接对象
        * @return Connection数据库连接对象
        * @throws SQLException
        */
        public static Connection getConnection() throws SQLException{
            return pool.getConnection();
        }

        /**
        * @Method: release
        * @Description: 释放资源,
        * 释放的资源包括Connection数据库连接对象,负责执行SQL命令的Statement对象,存储查询结果的ResultSet对象
        * @param conn
        * @param st
        * @param rs
        */
        public static void release(Connection conn,Statement st,ResultSet rs){
            if(rs!=null){
                try{
                    //关闭存储查询结果的ResultSet对象
                    rs.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
                rs = null;
            }
            if(st!=null){
                try{
                    //关闭负责执行SQL命令的Statement对象
                    st.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }

            if(conn!=null){
                try{
                    //关闭Connection数据库连接对象
                    conn.close();
                }catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }

}

调试代码:

package JDBC;

import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class TestJdbcPool {

    public static void main(String[] args) throws SQLException {
        //实例化封装了有关数据库类方法类的对象
        JdbcConnectionPoolTest jcpt=new JdbcConnectionPoolTest();
        //获得数据库连接对象
        Connection conn=jcpt.getConnection();
        //下面代码是存储过程的调用
        String s="call SP_select_nofilter6(?,?,?) ";
        CallableStatement cst=conn.prepareCall(s);
        cst.setInt(2, 2);
        cst.registerOutParameter(1, Types.VARCHAR);
        cst.registerOutParameter(3, Types.BLOB);
        ResultSet rs=cst.executeQuery();
        String name=cst.getString(1);
        Blob b=cst.getBlob(3);

        System.out.println("name:"+name+" Blob:"+b);
        //关闭所有的数据库资源
        jcpt.release(conn, cst, rs);
    }
}

运行结果:

获取到了链接com.mysql.jdbc.Connection@5f184fc6
获取到了链接com.mysql.jdbc.Connection@723279cf
获取到了链接com.mysql.jdbc.Connection@4e50df2e
获取到了链接com.mysql.jdbc.Connection@7cc355be
获取到了链接com.mysql.jdbc.Connection@52cc8049
获取到了链接com.mysql.jdbc.Connection@7530d0a
获取到了链接com.mysql.jdbc.Connection@4fca772d
获取到了链接com.mysql.jdbc.Connection@7cd84586
获取到了链接com.mysql.jdbc.Connection@70177ecd
获取到了链接com.mysql.jdbc.Connection@cc34f4d
linkedlist1数据库连接池大小是9
name:xiao Blob:com.mysql.jdbc.Blob@5197848c
com.mysql.jdbc.Connection@5f184fc6对象被释放,重新放回linkedlist集合中!
此时Linkedlist集合中有10个数据库连接对象!

标红的代码是比较重要的代码段~,其中Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h),返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序,loader参数定义代理类的类加载器,interfaces - 代理类要实现的接口列表,h - 指派方法调用的调用处理程序 。

三、两个开源的数据库连接池

在使用了数据库连接池之后,在项目的实际开发中就不需要编写连接数据库的代码了,直接从数据源获得数据库的连接。

1、dbcp连接

(1)导入相关jar包

commons-dbcp2-2.1.1.jar

commons-pool2-2.4.2.jar

commoms-logging-1.2.jar

(2)在项目根目录增加配置文件dbcp.properties

#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/jdbcstudy
username=root
password=XDP

#<!-- 初始化连接 -->
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=

#driver default 指定由连接池所创建的连接的事务级别(TransactionIsolation)。
#可用值为下列之一:(详情可见javadoc。)NONE,READ_UNCOMMITTED, READ_COMMITTED, REPEATABLE_READ, SERIALIZABLE
defaultTransactionIsolation=READ_UNCOMMITTED

(3)程序实现dbcp连接

代码演示:

数据库对象的代理类(封装Connection类的一些方法)

package DBCP;

import java.io.IOException;
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;

public class DBCPUtil {
    private static DataSource ds;
    private static final String configFile="/dbcp.properties";

    public DBCPUtil(){
        //实例化properties对象用于加载配置文件
        Properties prop=new Properties();
        InputStream is=DBCPUtil.class.getResourceAsStream(configFile);
        try {
            prop.load(is);
            ds=BasicDataSourceFactory.createDataSource(prop);
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
    /*
     * 获取数据库连接对象
     */
    public Connection getConn(){
        Connection conn=null;
        if(ds!=null){
            try {
                conn=ds.getConnection();
                conn.setAutoCommit(false);//设置禁止操作自动提交的情况
            } catch (SQLException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            return conn;
        }
        return conn;
    }
    /*
     * 封装数据库相关资源的关闭工作
     */
    public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
        if(rs!=null){
                rs.close();
        }
        if(st!=null){
                st.close();
        }
        if(conn!=null){
            conn.close();
        }
    }
}

代码调用:

package DBCP;

import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class DbcpTest {

    public static void main(String[] args) throws SQLException {
                //实例化数据库连接的代理类
                DBCPUtil dbcpUtil=new DBCPUtil();
                //获得数据库连接对象
                Connection conn=dbcpUtil.getConn();
                //下面代码是存储过程的调用
                String s="call SP_select_nofilter6(?,?,?) ";
                CallableStatement cst=conn.prepareCall(s);
                cst.setInt(2, 2);
                cst.registerOutParameter(1, Types.VARCHAR);
                cst.registerOutParameter(3, Types.BLOB);
                ResultSet rs=cst.executeQuery();
                String name=cst.getString(1);
                Blob b=cst.getBlob(3);

                System.out.println("name:"+name+" Blob:"+b);
                //关闭资源
                dbcpUtil.close(rs, cst, conn);
    }

}

运行结果:

name:xiao Blob:com.mysql.jdbc.Blob@30946e09

2、c3p0连接池

c3p0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定支持JDBC3和JDBC2的标准扩展

(1)导入相关的jar包

cc3p0-0.9.2-pre4.jar

mchange-commons-java-0.2.2.jar

如果是oracle数据库还需要添加c3p0-oracle-thin-extras-0.9.2-pre1.jar

(2)在项目根目录下增加配置文件

1)c3p0.properties

##配置除user,password,minpoolsize,maxpoolsize的参数
##[注意] 整数值不能有空格
#连接设置
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8
username=root
password=tiger

#初始化时获取三个连接,取值应在minPoolSize与maxPoolSize之间。Default: 3
c3p0.initialPoolSize=10

#当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3
c3p0.acquireIncrement=3

#最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0
#maxIdleTime应该小于MySQL的wait_timeout的值
c3p0.maxIdleTime=600

#定义在从数据库获取新连接失败后重复尝试的次数。Default: 30
c3p0.acquireRetryAttempts=5

#两次连接中间隔时间,单位毫秒。Default: 1000
c3p0.acquireRetryDelay=1000

#连接关闭时默认将所有未提交的操作回滚。Default: false
c3p0.autoCommitOnClose=false

#c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么
#属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试
#使用。Default: null
#c3p0.automaticTestTable=

#获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效
#保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试
#获取连接失败后该数据源将申明已断开并永久关闭。Default: false
#c3p0.breakAfterAcquireFailure=false

#当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出
#SQLException,如设为0则无限期等待。单位毫秒。Default: 0
c3p0.checkoutTimeout=10000

#每60秒检查所有连接池中的空闲连接。Default: 0
c3p0.idleConnectionTestPeriod=600

#JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements
#属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
#如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0
c3p0.maxStatements=100

#maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数。Default: 0
c3p0.maxStatementsPerConnection=0

#c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能
#通过多线程实现多个操作同时被执行。Default: 3
c3p0.numHelperThreads=3

2)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://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property>
        <property name="user">root</property>
        <property name="password">tiger</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://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8</property>
        <property name="user">root</property>
        <property name="password">tiger</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)编写类文件,创建连接池

1)c3p0.properties配置文件情况下

数据库对象的代理类(封装Connection类的一些方法)

package C3P0;

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

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util {

    private static ComboPooledDataSource ds=new ComboPooledDataSource();

    /*
     * 获取数据库连接对象
     */
    public static Connection getConnection() throws SQLException{
        return ds.getConnection();
    }

    /*
     * 封装数据库相关资源的关闭工作
     */
    public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
        if(rs!=null){
                rs.close();
        }
        if(st!=null){
                st.close();
        }
        if(conn!=null){
            conn.close();
        }
    }
}

代码调用:

package C3P0;

import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class C3P0Test {

    public static void main(String[] args) throws SQLException {
        C3P0Util c3p0Util=new C3P0Util();
        Connection conn=c3p0Util.getConnection();
        //下面代码是存储过程的调用
                String s="call SP_select_nofilter6(?,?,?) ";
                CallableStatement cst=conn.prepareCall(s);
                cst.setInt(2, 2);
                cst.registerOutParameter(1, Types.VARCHAR);
                cst.registerOutParameter(3, Types.BLOB);
                ResultSet rs=cst.executeQuery();
                String name=cst.getString(1);
                Blob b=cst.getBlob(3);

                System.out.println("name:"+name+" Blob:"+b);
                //关闭资源
                c3p0Util.close(rs, cst, conn);
    }
}

运行结果:

二月 14, 2017 7:36:12 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
二月 14, 2017 7:36:13 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 3, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> 2y4pm69mgrekqw18rvmvn|7aec35a, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgrekqw18rvmvn|7aec35a, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 15, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 3, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
name:xiao Blob:com.mysql.jdbc.Blob@31b7dea0

2)c3p0-config.xml配置文档情况下

数据库对象的代理类(封装Connection类的一些方法)

package C3P0;

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

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class C3P0Util1 {

    private static ComboPooledDataSource ds;

    /*
     * 获取数据库连接对象
     */
    public static Connection getConnection() throws SQLException{
        //通过代码创建C3P0数据库连接池
        /*ds = new ComboPooledDataSource();
        ds.setDriverClass("com.mysql.jdbc.Driver");
        ds.setJdbcUrl("jdbc:mysql://localhost:3306/jdbcstudy");
        ds.setUser("root");
        ds.setPassword("XDP");
        ds.setInitialPoolSize(10);
        ds.setMinPoolSize(5);
        ds.setMaxPoolSize(20);*/

        //通过读取C3P0的xml配置文件创建数据源,C3P0的xml配置文件c3p0-config.xml必须放在src目录下
        //ds = new ComboPooledDataSource();//使用C3P0的默认配置来创建数据源
        ds = new ComboPooledDataSource("MySQL");//使用C3P0的命名配置来创建数据源
        return ds.getConnection();
    }

    /*
     * 封装数据库相关资源的关闭工作
     */
    public void close(ResultSet rs,Statement st,Connection conn) throws SQLException{
        if(rs!=null){
                rs.close();
        }
        if(st!=null){
                st.close();
        }
        if(conn!=null){
            conn.close();
        }
    }
}

代码调用:

package C3P0;

import java.sql.Blob;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;

public class C3P0Test1 {

    public static void main(String[] args) throws SQLException {
        C3P0Util1 c3p0Util1=new C3P0Util1();
        Connection conn=c3p0Util1.getConnection();
        //下面代码是存储过程的调用
                String s="call SP_select_nofilter6(?,?,?) ";
                CallableStatement cst=conn.prepareCall(s);
                cst.setInt(2, 2);
                cst.registerOutParameter(1, Types.VARCHAR);
                cst.registerOutParameter(3, Types.BLOB);
                ResultSet rs=cst.executeQuery();
                String name=cst.getString(1);
                Blob b=cst.getBlob(3);

                System.out.println("name:"+name+" Blob:"+b);
                //关闭资源
                c3p0Util1.close(rs, cst, conn);
    }
}

运行结果:

二月 14, 2017 8:06:03 下午 com.mchange.v2.log.MLog
信息: MLog clients using java 1.4+ standard logging.
二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.C3P0Registry
信息: Initializing c3p0-0.9.5.2 [built 08-December-2015 22:06:04 -0800; debug? true; trace: 10]
二月 14, 2017 8:06:03 下午 com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource
信息: Initializing c3p0 pool... com.mchange.v2.c3p0.ComboPooledDataSource [ acquireIncrement -> 5, acquireRetryAttempts -> 5, acquireRetryDelay -> 1000, autoCommitOnClose -> false, automaticTestTable -> null, breakAfterAcquireFailure -> false, checkoutTimeout -> 10000, connectionCustomizerClassName -> null, connectionTesterClassName -> com.mchange.v2.c3p0.impl.DefaultConnectionTester, contextClassLoaderSource -> caller, dataSourceName -> MySQL, debugUnreturnedConnectionStackTraces -> false, description -> null, driverClass -> com.mysql.jdbc.Driver, extensions -> {}, factoryClassLocation -> null, forceIgnoreUnresolvedTransactions -> false, forceSynchronousCheckins -> false, forceUseNamedDriverClass -> false, identityToken -> 2y4pm69mgsgybs1qf3g8s|6e5e91e4, idleConnectionTestPeriod -> 600, initialPoolSize -> 10, jdbcUrl -> jdbc:mysql://127.0.0.1:3306/imooc?useUnicode=true&characterEncoding=utf-8, maxAdministrativeTaskTime -> 0, maxConnectionAge -> 0, maxIdleTime -> 600, maxIdleTimeExcessConnections -> 0, maxPoolSize -> 20, maxStatements -> 100, maxStatementsPerConnection -> 0, minPoolSize -> 5, numHelperThreads -> 3, preferredTestQuery -> null, privilegeSpawnedThreads -> false, properties -> {user=******, password=******}, propertyCycle -> 0, statementCacheNumDeferredCloseThreads -> 0, testConnectionOnCheckin -> false, testConnectionOnCheckout -> false, unreturnedConnectionTimeout -> 0, userOverrides -> {}, usesTraditionalReflectiveProxies -> false ]
name:xiao Blob:com.mysql.jdbc.Blob@c39f790

总结:其实不管配置文件是c3p0.properties还是c3p0-config.xml,其代码实现部分没有多大区别,唯一区别可能就是c3p0-config.xml情况下可以调用含参的ComboPooledDataSource(String s)构造函数,两个都可以调用其默认的无参构造函数。

3、dbcp和c3p0不同之处

dbcp c3p0
spring组织推荐使用 Hibernate组织推荐使用
强制关闭连接或者数据库重启后无法自动重连 强制关闭连接或者数据库重启可以自动连接
没有自动的去回收空闲连接的功能 自动回收空闲的功能
DBCP提供最大连接数
c3p0提供最大空闲时间

dbcp并没用相应功能 c3p0可以控制数据源加载的prepareedstatement数量,并且可以设置帮助线程的数量来提升JDBC操作速度

以上所述是小编给大家介绍的Java中JDBC连接池的基本原理及实现方式,希望对大家有所帮助。在此也非常感谢大家对我们网站的支持!

(0)

相关推荐

  • 自定义一个简单的JDBC连接池实现方法

    一.什么是JDBC连接池? 在传统的JDBC连接中,每次获得一个Connection连接都需要加载通过一些繁杂的代码去获取,例如以下代码: public static Connection getConn(){ Connection conn = null; String url = "jdbc:mysql://localhost:3306/test"; String user = "root"; String password = "root"

  • Spring 数据库连接池(JDBC)详解

    数据库连接池 对一个简单的数据库应用,由于对数据库的访问不是很频繁,这时可以简单地在需要访问数据库时,就新创建一个连接,就完后就关闭它,这样做也不会带来什么性能上的开销.但是对于一个复杂的数据库应用,情况就完全不同而,频繁的建立.关闭连接,会极大地减低系统的性能,因为对于连接的使用成了系统性能的瓶颈. 通过建立一个数据库连接池以及一套连接使用管理策略,可以达到连接复用的效果,使得一个数据库连接可以得到安全.高效的复用,避免了数据库连接频繁建立.关闭的开销. 数据库连接池的基本原理是在内部对象池中

  • JDBC数据源连接池配置及应用

    使用JDBC建立数据库连接的两种方式: 1.在代码中使用DriverManager获得数据库连接.这种方式效率低,并且其性能.可靠性和稳定性随着用户访问量得增加逐渐下降. 2.使用配置数据源的方式连接数据库,该方式其实质就是在上述方法的基础上增加了数据库连接池,这种方式效率高. 数据源连接池的方式连接数据库与在代码中使用DriverManager获得数据库连接存在如下差别: 1)数据源连接池的方式连接数据库是在程序中,通过向一个JNDI(Java Naming and  Directory In

  • JDBC自定义连接池过程详解

    这篇文章主要介绍了JDBC自定义连接池过程详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 开发中,"获得连接"和"释放资源"是非常消耗系统资源的,为了解决此类性能问题可以采用连接池技术来共享连接Connection. 1.概述 用池来管理Connection,这样可以重复使用Connection.这样我们就不用创建Connection,用池来管理Connection对象,当使用完Connection对象后,将C

  • JDBC利用C3P0数据库连接池连接数据库

    JDBC之C3P0数据库连接池,供大家参考,具体内容如下 1 首先在src中创建c3p0-config.xml 配置文件,文件中内容如下(首先下载C3P0.jar工具包 并放入项目环境变量中) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE xml> <c3p0-config> <!--下面四个是数据库连接必须需要的东西 --> <named-config nam

  • Java中JDBC连接池的基本原理及实现方式

    目录 一. 应用程序直接建立数据库连接模型 二.使用数据库连接池优化模型 1.关于连接池中的连接数量的一些规定: 2.编写数据库连接池 创建数据库连接池: 进一步封装一些相关数据库的类的方法 三.两个开源的数据库连接池 1.dbcp连接 (1)导入相关jar包 (2)在项目根目录增加配置文件dbcp.properties (3)程序实现dbcp连接 2.c3p0连接池 (1)导入相关的jar包 (2)在项目根目录下增加配置文件 (3)编写类文件,创建连接池 3.dbcp和c3p0不同之处 一.

  • Java中Druid连接池连接超时获取不到连接的解决

    错误内容: com.alibaba.druid.pool.GetConnectionTimeoutException: wait millis 30000, active 600, maxActive 600, creating 0 detail: Service Error:Cannot find a proper coonection from STDB 错误日志截图: 解决过程: 1.添加了三个参数 作用是如果超过3分钟,连接未释放,那么关闭连接,并报错. 2.进行请求,并查看日志 确认获

  • MyBatis中的连接池及事物控制配置过程

    目录 1.连接池 2.mybatis中的事物 1.if语句的设置 2.mybatis中的多表查询 1.连接池 在实际开发中都会使用连接池因为它可以减少我们获取连接所消耗的时间 连接池就是用于存储连接的一个容器,容器其实就是一个集合对象,该集合必须是线程安全的,不能两个线程拿到统一连接,该集合还必须实现队列特性:先进先出 Mybatis连接提供了.种方式的怕配置: 配置位置:主配置文件SqlMapConfig.xml中的dataSource标签,type属性就是标识采用何种连接池方式 type属性

  • Java实现数据连接池Druid举例

    目录 开篇 Druid的调试 参考 开篇 Druid号称是Java语言中最好的数据库连接池,并且能够提供强大的监控和扩展功能.作为日常使用较多的数据库连接组件,纯粹个人兴趣研究下理解下的实现原理. 理解一个工具组件最好的方式就是进行 debug,这里建议大家下载下参考连接中的 druid demo,修改下具体的数据库连接参数就可以直接进行调试跟踪. 之所以强调 Demo 的重要性,在于通过 demo 能够跟踪所有的执行流程,有了 Demo 剩下的事情只要花时间都能很好的梳理. Druid的调试

  • JSP Spring中Druid连接池配置详解

    JSP Spring中Druid连接池配置 jdbc.properties url=jdbc:postgresql://***.***.***.***:****/**** username=*** password=*** applicationContext.xml中配置bean <!-- 阿里 druid 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSou

  • java基于jdbc连接mysql数据库功能实例详解

    本文实例讲述了java基于jdbc连接mysql数据库的方法.分享给大家供大家参考,具体如下: 一.JDBC简介 Java 数据库连接,(Java Database Connectivity,简称JDBC)是Java语言中用来规范客户端程序如何来访问数据库的应用程序接口,提供了诸如查询和更新数据库中数据的方法.JDBC也是Sun Microsystems的商标.它JDBC是面向关系型数据库的. 1.JDBC架构: JDBC API支持两层和三层处理模型进行数据库访问,但在一般的JDBC体系结构由

  • java 中JDBC连接数据库代码和步骤详解及实例代码

    java 中JDBC连接数据库代码和步骤详解 JDBC连接数据库 •创建一个以JDBC连接数据库的程序,包含7个步骤:  1.加载JDBC驱动程序:  在连接数据库之前,首先要加载想要连接的数据库的驱动到JVM(Java虚拟机),这通过java.lang.Class类的静态方法forName(String  className)实现. 例如: try{ //加载MySql的驱动类 Class.forName("com.mysql.jdbc.Driver") ; }catch(Class

  • Java中JDBC实现动态查询的实例详解

    一 概述 1.什么是动态查询? 从多个查询条件中随机选择若干个组合成一个DQL语句进行查询,这一过程叫做动态查询. 2.动态查询的难点 可供选择的查询条件多,组合情况多,难以一一列举. 3.最终查询语句的构成 一旦用户向查询条件中输入数据,该查询条件就成为最终条件的一部分. 二 基本原理 1.SQL基本框架 无论查询条件如何,查询字段与数据库是固定不变的,这些固定不变的内容构成SQL语句的基本框架,如 select column... from table. 2.StringBuilder形成D

  • Java使用jdbc连接MySQL数据库实例分析

    本文实例讲述了Java使用jdbc连接MySQL数据库的方法.分享给大家供大家参考,具体如下: 使用jdbc连接数据库: 可以直接在方法中定义url.user.psd等信息,也可以读取配置文件,但是在web项目中肯定是要使用第二种方式的,为了统一,只介绍第二种方式. 步骤 1.创建配置文件db.properties 无论是eclipse还是myeclipse,在工程下右键->new->file,以properties为后缀名就好了. 配置文件内容: #连接数据库的url,如果主机地址是loca

随机推荐