1 简介

数据库连接是一种关键的有限的昂贵的资源,这一点在多用户的网页应用程序中体现得尤为突出。对数据库连接的管理能显著影响到整个应用程序的伸缩性和健壮性,影响到程序的性能指标。数据库连接池正是针对这个问题提出来的。
    数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。

java数据库连接池原理 java数据库连接池的作用_java


2连接池种类

本文最后提供示例下载!!!!

  • C3P0
  • Druid
  • JNDI
  • DBCP
  • proxool
  • BoneCP

    3代码示例
    我采用的是maven工程搭建项目spring+mybatis+mysql
    maven->poi.xml
<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>4.0.2.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.4.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.4.1</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.0</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>6.0.6</version>
    </dependency>
    <!-- druid 数据库连接池 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.3</version>
    </dependency>
    <!-- c3p0 数据库连接池 -->
    <dependency>
        <groupId>c3p0</groupId>
        <artifactId>c3p0</artifactId>
        <version>0.9.1.2</version>
    </dependency>
    <!-- apache dbcp 数据库连接池 -->
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
    <!-- jndi -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-mock</artifactId>
        <version>2.0.8</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>simple-jndi</groupId>
        <artifactId>simple-jndi</artifactId>
        <version>0.11.4.1</version>
        <scope>test</scope>
    </dependency>
    <!-- proxool -->
    <dependency>
        <groupId>com.cloudhopper.proxool</groupId>
        <artifactId>proxool</artifactId>
        <version>0.9.1</version>
    </dependency>
    <!-- bonecp -->
    <dependency>
      <groupId>com.jolbox</groupId>
      <artifactId>bonecp-spring</artifactId>
      <version>0.8.0.RELEASE</version>
    </dependency>
</dependencies>

新建 TestDao ,Test_Mapper.xml,Test

package com.zhs.test.dao;

import java.util.List;

import org.springframework.stereotype.Repository;

@Repository
public interface TestDao {

    List<com.zhs.test.empty.Test> getTestList();

}
package com.zhs.test.empty;

public class Test {

    private String name;
    private Integer age;
    private String sex;

    public Test(String name, Integer age, String sex) {
        super();
        this.name = name;
        this.age = age;
        this.sex = sex;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public String getSex() {
        return sex;
    }
    public void setSex(String sex) {
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "Test [name=" + name + ", age=" + age + ", sex=" + sex + "]";
    }




}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--命名空间应该是对应接口的包名+接口名 -->
<mapper namespace="com.zhs.test.dao.TestDao">

    <resultMap type="com.zhs.test.empty.Test" id="BaseResultMap">
        <constructor>
            <arg column="name" jdbcType="VARCHAR" javaType="java.lang.String"/>
            <arg column="age" jdbcType="INTEGER" javaType="java.lang.Integer"/>
            <arg column="sex" jdbcType="VARCHAR" javaType="java.lang.String"/>
        </constructor>
    </resultMap>
    <select id="getTestList" resultMap="BaseResultMap">
        select name,age,sex from test
    </select>
</mapper>

数据库新建Test表

java数据库连接池原理 java数据库连接池的作用_数据库连接池_02

  • C3P0
    c3p0配置文件和测试样例
    新建 applicationContext-c3p0.xml
    配置文件中已全部给出详细解释,不一一详述。
<!-- 全局context类配置 -->
        <mvc:annotation-driven />
        <context:component-scan base-package="com.zhs.test"></context:component-scan>

        <!-- C3P0 数据库连接池 -->
        <bean id="dataSource"  class="com.mchange.v2.c3p0.ComboPooledDataSource"  destroy-method="close">  
            <property name="driverClass" value="com.mysql.jdbc.Driver" /> 
            <property name="jdbcUrl" value="jdbc:mysql://139.159.219.106:3306/ch9188?useUnicode=true&characterEncoding=utf8"/>    
            <property name="user" value="root"/>  
            <property name="password" value="zhs123147"/> 
            <!--连接池中保留的最小连接数。-->  
            <property name="minPoolSize" value="5"/> 
             <!--连接池中保留的最大连接数。Default: 15 --> 
            <property name="maxPoolSize" value="50"/> 
            <!--初始化时获取的连接数,取值应在minPoolSize与maxPoolSize之间。Default: 3 -->  
            <property name="initialPoolSize" value="10"/> 
            <!--最大空闲时间,60秒内未使用则连接被丢弃。若为0则永不丢弃。Default: 0 -->  
            <property name="maxIdleTime" value="60"/> 
            <!--当连接池中的连接耗尽的时候c3p0一次同时获取的连接数。Default: 3 -->  
            <property name="acquireIncrement" value="5"/> 
            <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements  
      属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。  
      如果maxStatements与maxStatementsPerConnection均为0,则缓存被关闭。Default: 0-->  
            <property name="maxStatements" value="0"/> 
            <!--每60秒检查所有连接池中的空闲连接。Default: 0 --> 
            <property name="idleConnectionTestPeriod" value="60"/> 
            <!--定义在从数据库获取新连接失败后重复尝试的次数。Default: 30 -->  
            <property name="acquireRetryAttempts" value="30"/> 
             <!--获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效  
              保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试  
              获取连接失败后该数据源将申明已断开并永久关闭。Default: false-->  
            <property name="breakAfterAcquireFailure" value="true"/> 
            <!--因性能消耗大请只在需要的时候使用它。如果设为true那么在每个connection提交的  
              时候都将校验其有效性。建议使用idleConnectionTestPeriod或automaticTestTable  
              等方法来提升连接测试的性能。Default: false -->  
            <property name="testConnectionOnCheckout" value="false"/>   
        </bean>  
        <!-- 配置sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--            <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> -->
            <property name="dataSource" ref="dataSource" />
            <property name="mapperLocations">
                <list>
                    <value>classpath:mybatis/sqlmap/*Mapper.xml</value>
                </list>
            </property>
        </bean>
        <!-- 通过扫描的模式,自动注入bean -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zhs.test" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

新建TestC3P0.java测试类

package com.zhs.test;

import java.util.List;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.zhs.test.dao.TestDao;

public class TestC3p0 {

    public static void main(String[] args) {
        String path = "classpath:mybatis/applicationContext-c3p0.xml";
        GenericXmlApplicationContext context = new GenericXmlApplicationContext(path);
        context.start();

        TestDao testDao = context.getBean(TestDao.class);
        List<com.zhs.test.empty.Test> TestList = testDao.getTestList();
        for(com.zhs.test.empty.Test test:TestList){
            System.out.println(test);
        }


    }

}
  • Druid
    Druid 配置文件和测试样例
    新建 applicationContext-druid.xml
    配置文件中已全部给出详细解释,不一一详述。
    新建applicationContext-druid.xml
<!-- 全局context类配置 -->
        <mvc:annotation-driven />
        <context:component-scan base-package="com.zhs.test"></context:component-scan>

        <!-- 阿里 druid 数据库连接池 -->
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
              init-method="init" destroy-method="close">
            <property name="driverClassName" value="com.mysql.jdbc.Driver" />
            <!-- 139.159.219.106 -->
            <property name="url" value="jdbc:mysql://139.159.219.106:3306/ch9188?useUnicode=true&characterEncoding=utf8" />
            <property name="username" value="root" />
            <property name="password" value="zhs123147" />
            <!-- 配置初始化大小、最小、最大 -->
            <property name="initialSize" value="1" />
            <property name="minIdle" value="1" />
            <property name="maxActive" value="10" />

            <!-- 配置获取连接等待超时的时间 -->
            <property name="maxWait" value="10000" />

            <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
            <property name="timeBetweenEvictionRunsMillis" value="60000" />

            <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
            <property name="minEvictableIdleTimeMillis" value="300000" />

            <property name="testWhileIdle" value="true" />

            <!-- 这里建议配置为TRUE,防止取到的连接不可用 -->
            <property name="testOnBorrow" value="true" />
            <property name="testOnReturn" value="false" />

            <!-- 打开PSCache,并且指定每个连接上PSCache的大小 -->
            <property name="poolPreparedStatements" value="true" />
            <property name="maxPoolPreparedStatementPerConnectionSize"
                      value="20" />

            <!-- 这里配置提交方式,默认就是TRUE,可以不用配置 -->

            <property name="defaultAutoCommit" value="true" />

            <!-- 验证连接有效与否的SQL,不同的数据配置不同 -->
            <property name="validationQuery" value="select 1 " />
            <property name="filters" value="stat,log4j" />
        </bean>
        <!-- 配置sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--            <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> -->
            <property name="dataSource" ref="dataSource" />
            <property name="mapperLocations">
                <list>
                    <value>classpath:mybatis/sqlmap/*Mapper.xml</value>
                </list>
            </property>
        </bean>
        <!-- 通过扫描的模式,自动注入bean -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zhs.test" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

新建测试类

package com.zhs.test;

import java.util.List;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.zhs.test.dao.TestDao;

public class TestDruid {

    public static void main(String[] args) {
        String path = "classpath:mybatis/applicationContext-datasource.xml";
        GenericXmlApplicationContext context = new GenericXmlApplicationContext(path);
        context.start();

        TestDao testDao = context.getBean(TestDao.class);
        List<com.zhs.test.empty.Test> TestList = testDao.getTestList();
        for(com.zhs.test.empty.Test test:TestList){
            System.out.println(test);
        }


    }

}
  • JNDI
    JNDI 这个示例由于我自己的技术有限,调试一直失败,有兴趣的朋友可以自己下载调试下,源码在最后面!
  • DBCP
    DBCP 配置文件和测试样例
    配置文件中已全部给出详细解释,不一一详述。
    新建applicationContext-dbcp.xml
<!-- 全局context类配置 -->
        <mvc:annotation-driven />
        <context:component-scan base-package="com.zhs.test"></context:component-scan>

        <!-- dbcp 数据库连接池 -->
        <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
            <!-- 加载驱动 -->
            <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
            <!-- 数据库的名字 -->
            <property name="url" value="jdbc:mysql://139.159.219.106:3306/ch9188?useUnicode=true&characterEncoding=utf8"></property>
            <!-- 用户名密码 -->
            <property name="username" value="root"></property>
            <property name="password" value="zhs123147"></property>
            <!-- 最大连接数 -->
            <property name="maxActive" value="10000"></property>
            <!-- 最大可空闲 -->
            <property name="maxIdle" value="0"></property>
            <!-- 最大等待秒数,单位为毫秒, 超过时间会报出错误信息 -->
            <property name="maxWait" value="1000"></property>
            <!-- 默认自动提交,跟事务有关系,true,每执行就会提交,所以没有事务 -->
            <property name="defaultAutoCommit" value="false"></property>
        </bean>
        <!-- 配置sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--            <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> -->
            <property name="dataSource" ref="dataSource" />
            <property name="mapperLocations">
                <list>
                    <value>classpath:mybatis/sqlmap/*Mapper.xml</value>
                </list>
            </property>
        </bean>
        <!-- 通过扫描的模式,自动注入bean -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zhs.test" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

新建测试类

package com.zhs.test;

import java.util.List;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.zhs.test.dao.TestDao;

public class TestDBCP {

    public static void main(String[] args) {
        String path = "classpath:mybatis/applicationContext-dbcp.xml";
        GenericXmlApplicationContext context = new GenericXmlApplicationContext(path);
        context.start();

        TestDao testDao = context.getBean(TestDao.class);
        List<com.zhs.test.empty.Test> TestList = testDao.getTestList();
        for(com.zhs.test.empty.Test test:TestList){
            System.out.println(test);
        }


    }

}
  • proxool
    proxool 配置文件和测试样例
    新建 applicationContext-proxool.xml
<!-- 全局context类配置 -->
        <mvc:annotation-driven />
        <context:component-scan base-package="com.zhs.test"></context:component-scan>

        <!--springjdbc 数据库连接池 -->
        <bean id="dataSource" class="org.logicalcobwebs.proxool.ProxoolDataSource">
            <property name="driver">
                <value>com.mysql.jdbc.Driver</value>
            </property>
            <property name="driverUrl">
                <value>jdbc:mysql://139.159.219.106:3306/ch9188?useUnicode=true&characterEncoding=utf8</value>
            </property>
            <property name="user" value="root" />
            <property name="password" value="zhs123147" />
            <property name="alias" value="Pool_dbname" />
<!--            <property name="houseKeepingSleepTime" value="90000" />
 -->            <property name="prototypeCount" value="0" />
            <property name="maximumConnectionCount" value="50" />
            <property name="minimumConnectionCount" value="2" />
            <property name="simultaneousBuildThrottle" value="50" />
            <property name="maximumConnectionLifetime" value="14400000" />
            <property name="houseKeepingTestSql" value="select CURRENT_DATE" />
        </bean>
        <!-- 配置sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--            <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> -->
            <property name="dataSource" ref="dataSource" />
            <property name="mapperLocations">
                <list>
                    <value>classpath:mybatis/sqlmap/*Mapper.xml</value>
                </list>
            </property>
        </bean>
        <!-- 通过扫描的模式,自动注入bean -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zhs.test" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

配置文件中已全部给出详细解释,不一一详述。
新建测试类

package com.zhs.test;

import java.util.List;

import org.logicalcobwebs.proxool.ProxoolDataSource;
import org.springframework.context.support.GenericXmlApplicationContext;

import com.zhs.test.dao.TestDao;

public class TestProxool {

    public static void main(String[] args) {
        String path = "classpath:mybatis/applicationContext-proxool.xml";
        GenericXmlApplicationContext context = new GenericXmlApplicationContext(path);
        context.start();

        TestDao testDao = context.getBean(TestDao.class);
        List<com.zhs.test.empty.Test> TestList = testDao.getTestList();
        for(com.zhs.test.empty.Test test:TestList){
            System.out.println(test);
        }


    }

}
  • BoneCP
    配置文件中已全部给出详细解释,不一一详述。
    JNDI 配置文件和测试样例
    新建 applicationContext-bonecp.xml
<!-- 全局context类配置 -->
        <mvc:annotation-driven />
        <context:component-scan base-package="com.zhs.test"></context:component-scan>

        <!-- Spring BoneCP 数据源配置-->
        <bean id="dataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
            <!-- 数据库驱动 -->
            <property name="driverClass" value="com.mysql.jdbc.Driver" />
            <!-- 相应驱动的jdbcUrl -->
            <property name="jdbcUrl" value="jdbc:mysql://139.159.219.106:3306/ch9188?useUnicode=true&characterEncoding=utf8" />
            <!-- 数据库的用户名 -->
            <property name="username" value="root" />
            <!-- 数据库的密码 -->
            <property name="password" value="zhs123147" />
            <!-- 检查数据库连接池中空闲连接的间隔时间,单位是分,默认值:240,如果要取消则设置为0 -->
            <property name="idleConnectionTestPeriod" value="60" />
            <!-- 连接池中未使用的链接最大存活时间,单位是分,默认值:60,如果要永远存活设置为0 -->
            <property name="idleMaxAge" value="30" />
            <!-- 每个分区最大的连接数 -->
            <property name="maxConnectionsPerPartition" value="150" />
            <!-- 每个分区最小的连接数 -->
            <property name="minConnectionsPerPartition" value="5" />
        </bean>
        <!-- 配置sqlSessionFactory -->
        <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<!--            <property name="configLocation" value="classpath:mybatis/mybatis-config.xml"/> -->
            <property name="dataSource" ref="dataSource" />
            <property name="mapperLocations">
                <list>
                    <value>classpath:mybatis/sqlmap/*Mapper.xml</value>
                </list>
            </property>
        </bean>
        <!-- 通过扫描的模式,自动注入bean -->
        <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
            <property name="basePackage" value="com.zhs.test" />
            <property name="sqlSessionFactoryBeanName" value="sqlSessionFactory"/>
        </bean>

新建测试类

package com.zhs.test;

import java.util.List;

import org.springframework.context.support.GenericXmlApplicationContext;

import com.zhs.test.dao.TestDao;

public class TestBoneCP {

    public static void main(String[] args) {
        String path = "classpath:mybatis/applicationContext-bonecp.xml";
        GenericXmlApplicationContext context = new GenericXmlApplicationContext(path);
        context.start();

        TestDao testDao = context.getBean(TestDao.class);
        List<com.zhs.test.empty.Test> TestList = testDao.getTestList();
        for(com.zhs.test.empty.Test test:TestList){
            System.out.println(test);
        }


    }

}

4总结
个人见解,目前常用的C3P0在项目中第一次启动连接时有问题,需要多尝试几次。druid在如果长期无连接第一点击连接比较迟钝,druid自带监控页面在web.xml中配置即可使用,代码:

<servlet>
        <!-- sql 栏显示 -->
        <servlet-name>DruidStatView</servlet-name>
        <servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
        <init-param>
            <!-- 允许清空统计数据 -->
            <param-name>resetEnable</param-name>
            <param-value>true</param-value>
        </init-param>
        <init-param>
            <!-- 用户名 -->
            <param-name>loginUsername</param-name>
            <param-value>druid</param-value>
        </init-param>
        <init-param>
            <!-- 密码 -->
            <param-name>loginPassword</param-name>
            <param-value>druid</param-value>
        </init-param>
    </servlet>

PS:源码下载地址:http://pan.baidu.com/s/1jIOjoz0
下载地址: