数据连接池C3P0/DBCP/DRUID/自定义连接池

1.C3P0连接池

快速入门官网  https://www.mchange.com/projects/c3p0/#quickstart  

<dependency>
			<groupId>com.mchange</groupId>
			<artifactId>c3p0</artifactId>
			<version>0.9.5.2</version>
</dependency>
public class C3P0Pool {
	public static void main(String[] args) throws PropertyVetoException, SQLException {
		ComboPooledDataSource cpds = new ComboPooledDataSource();
		cpds.setDriverClass("com.mysql.cj.jdbc.Driver"); 
		cpds.setJdbcUrl("jdbc:mysql://localhost:3306/table?useUnicode="
				+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
				+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
		cpds.setUser("root");
		cpds.setPassword("cgz12345678");
		//最大8
		cpds.setMaxPoolSize(8);
		//最小2个
		cpds.setMinPoolSize(2);
		//初始化2 介于MinPoolSize(2)与MaxPoolSize(8)之间
		cpds.setInitialPoolSize(2);
		//当连接数不足时每次补充2个
		cpds.setAcquireIncrement(2);
		//维护statement的总个数
		cpds.setMaxStatements(70);
		//每个连接可以使用的statement的个数
		cpds.setMaxStatementsPerConnection(10);
		//最大保持的空闲时间,否则被回收  与maxConnectionAge的区别是maxConnectionAge表示活着的总时间
		cpds.setMaxIdleTime(60000);
		Connection connection = cpds.getConnection();
		System.out.println(connection);
	}
}
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <named-config name="c3p0">
        <!-- 配置数据库链接地址 -->
        <property name="jdbcUrl">jdbc:mysql://localhost:3306/user?useUnicode=true&characterEncoding=utf8&characterSetResults=utf8&useSSL=false&verifyServerCertificate=false&serverTimezone=GMT%2B8</property>
        <!-- 配置数据库驱动 -->
        <property name="driverClass">com.mysql.jdbc.Driver</property>
        <!-- 当不足时,数据库连接池一次性向数据库要多少个连接对象 ,Default:3-->
        <property name="acquireIncrement">20</property>
        <!-- 初始化连接数,Default:3 -->
        <property name="initialPoolSize">10</property>
        <!-- 最小连接数 -->
        <property name="minPoolSize">5</property>
        <!--最大连接数。Default: 15 -->
        <property name="maxPoolSize">30</property>
        <!--JDBC的标准参数,用以控制数据源内加载的PreparedStatements数量。但由于预缓存的statements 属于单个connection而不是整个连接池。所以设置这个参数需要考虑到多方面的因素。
如果maxStatements为0,那么maxStatementsPerConnection无效,则缓存被关闭。Default:0 --> <property name="maxStatements">0</property> <!--maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数如果设置的好能提高性能。Default: 0 --> <property name="maxStatementsPerConnection">0</property> <!--c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能 通过多线程实现多个操作同时被执行。Default:3 --> <property name="numHelperThreads">3</property> <!--用户修改系统配置参数执行前最多等待300秒。Default: 300 --> <property name="propertyCycle">300</property> <!-- 获取连接超时设置 默认是一直等待,单位毫秒 --> <property name="checkoutTimeout">1000</property> <!--每多少秒检查所有连接池中的空闲连接。Default: 0 --> <property name="idleConnectionTestPeriod">3</property> <!--最大空闲时间,多少秒内未被使用则连接被丢弃。若为0则永不丢弃。单位秒,Default: 0 --> <property name="maxIdleTime">10</property> <!--配置连接的生存时间,单位秒,超过这个时间的连接将由连接池自动断开丢弃掉。当然正在使用的连接不会马上断开,而是等待它close再断开。配置为0的时候则不会对连接的生存时间进行限制。
不为0则保持到minPoolSize --> <property name="maxIdleTimeExcessConnections">5</property> <!--两次连接中间隔时间,单位毫秒。Default: 1000 --> <property name="acquireRetryDelay">1000</property> <!--c3p0将建一张名为Test的空表,并使用其自带的查询语句进行测试。如果定义了这个参数那么属性preferredTestQuery将被忽略。你不能在这张Test表上进行任何操作,它将只供c3p0测试使用。Default: null --> <property name="automaticTestTable">Test</property> <!-- 获取connnection时测试是否有效 --> <property name="testConnectionOnCheckin">true</property>
     <!-- 活着的总时间,单位秒 -->
     <property name="maxConnectionAge">12</property> </named-config> </c3p0-config>

备注:可以按上述提供的官网书写相应的xml文件,或者是properties文件,但是名称分别必须为c3p0-config.xml和c3p0.properties,否则找不到,一个xml中可以配置多个c3p0但是<named-config name="c3p0"> 的name不同,假如在maven的 srcmain esources目录下,那么上述的获取方式为ComboPooledDataSource cpds = new ComboPooledDataSource("c3p0");

2.DBCP

api文档: http://commons.apache.org/proper/commons-dbcp/api-2.5.0/index.html  

public class DBCPPoolTest {
	public static void main(String[] args) throws SQLException {
		BasicDataSource dataSource = new BasicDataSource();
		dataSource.setUsername("root");
		dataSource.setUrl("jdbc:mysql://localhost:3306/table?useUnicode="
				+ "true&characterEncoding=utf8&characterSetResults=utf8&useSSL="
				+ "false&verifyServerCertificate=false&serverTimezone=GMT%2B8 ");
		dataSource.setPassword("12345678");
		dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
		dataSource.setInitialSize(1);// 初始化连接数
		// 超过8个connection在规定的的等待时间之内得不到连接则会报错
		dataSource.setMaxTotal(8);// 最大连接数
		// 超过maxIdle值后,刚刚使用完的连接(刚刚空闲下来)会立即被销毁。
		dataSource.setMaxIdle(3);// 最大的空闲数,一般设置为MaxTotal的一半
		dataSource.setMinIdle(2);// 默认是0 ,一般设置比较小为好,尽量减少连接数的空闲占用,当不足以保证时,就维持现状,当有还给连接池的对象时,又添加来保持自己
		dataSource.setMaxWaitMillis(60000);// 连接池分配连接的最大时间,超过会报出异常
		// 池中的连接空闲时间,超过被回收默认值就是30分钟
		dataSource.setMinEvictableIdleTimeMillis(3000000);
		Connection con = dataSource.getConnection();
		System.out.println(con);
		con.close();// 并非真正的关闭,而是将其归还到线程池
		dataSource.close();
	}
}
#类似c3p0的driverClass
driverClassName=com.mysql.jdbc.Driver 
#传递给JDBC驱动的用于建立连接的URL
#当设置characterEncoding时useUnicode=true必须设置,characterEncoding指按指定编码解码成字节码,autoReconnect=true当数据库连接中断时是否自动重新连接,autoReconnect=true但是这个连接两次访问数据库的时间超出了服务器端wait_timeout的时间限制,还是会CommunicationsException,dontTrackOpenResources要求驱动自动跟踪和关闭资源,如果不能明确的调用作用在语句或者结果集上的close时,会造成内存溢出,设置为true可以提高某些程序的内存效率 默认false
url=jdbc:mysql://localhost:3306/testjdbc?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&dontTrackOpenResources=true
#传递给JDBC驱动的用于建立连接的用户名
username=root
#传递给JDBC驱动的用于建立连接的密码
password=cgz12345678
#初始化连接:初始化连接数量,1.2版本后支持  默认值0  jdbc-pool默认值10
initialSize=5
#最大活动连接:如果设置为非正数则表示不限制 默认值8 jdbc-pool默认值100
maxActive=8
#最大空闲连接:超过的空闲连接将被释放,如果设置为负数表示不限制 默认值8 jdbc-pool默认值
maxIdle=20
#最小空闲连接,低于这个数量将创建新的连接,如果设置为0则不创建 默认值0 jdbc-pool默认值10
minIdle=5
#最大等待时间: (以毫秒计数),超过时间则抛出异常,如果设置为-1表示无限等待 默认值:无限  jdbc-pool默认值30000ms
maxWait=28000
#连接池创建的连接的默认的auto-commit状态,默认值true
defaultAutoCommit=true
#当设置了set-onlyread,则默认值为only-read模式,当没有设置的时候不会被调用,(不支持只读模式) (某些驱动不支持只读模式,比如:Informix)
defaultReadOnly 
#连接池创建的连接的默认的TransactionIsolation状态. Jdbc事物隔离级别中的一个
defaultTransactionIsolation= READ_COMMITTED
#连接池创建的连接的默认的catalog
defaultCatalog
#是否自动回收超时连接,默认值false,这个是由前提条件的,当空闲连接数小于一定数量的时候才会被触发,类似垃圾回收,回收的前提是响应时间超过removeAbandonedTimeout时间
removeAbandoned=true
#超过相应的时间没响应就回收, 单位秒 默认300
removeAbandonedTimeout=300
#是否在自动回收超时连接的时候打印连接的超时错误,默认值false jdbc-pool默认值false
logAbandoned=true
#SQL查询验证语句至少返回一条语句
 validationQuery=select 1
#指明是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个.
#如果设置为true后如果要生效那么validationQuery参数必须设置为非空字符串 默认值:true,对连接前进行相应的检验,检验失败,则删除连接,尝试下一条连接
testOnBorrow=true
#注意: 设置为true后如果要生效,validationQuery参数必须设置为非空字符串   默认值: false jdbc-pool默认值false,指明是否在归还到池中前进行检验
testOnReturn=true
#指明连接是否被空闲连接回收器(如果有)进行检验.如果检测失败(检测是以timeBetweenEvictionRunsMilli为依据,如果超过这个时间则进行validationQuery检测连接是否有效),则连接将被从池中去除.设置为true后如果要生效,validationQuery参数必须设置为非空字符串  默认值: false
testWhileIdle=true
#空闲连接回收器线程运行时间间隔,以毫秒为单位. 如果设置为非正数,则不运行空闲连接回收器线程  默认值: -1  jdbc-pool的默认值为5000ms
timeBetweenEvictionRunsMilli=-1
#每次空闲连接回收器线程(如果有)运行时检查的连接数量 默认值:1000 * 60 * 30
numTestsPerEvictionRun
#保存空闲而不被空闲回收器回收的间隔时间
minEvictableIdleTimeMillis
#开启池的prepared statement 池功能  默认值false
poolPreparedStatements
#statement池能够同时分配的打开的statements的最大数量, 如果设置为0表示不限制 默认值:不限制
maxOpenPreparedStatements=0
#这里可以开启PreparedStatements池. 当开启时, 将为每个连接创建一个statement池,并且被下面方法创建的PreparedStatements将被缓存起来:
#PoolGuard是否容许获取底层连接 默认值false
#如果容许则可以使用下面的方式来获取底层连接:
 #   Connection conn = ds.getConnection();
 #   Connection dconn = ((DelegatingConnection) conn).getInnermostDelegate();
 #  ...
 #   conn.close();
#注意: 不要关闭底层连接, 只能关闭前面的那个.
accessToUnderlyingConnectionAllowed
4.2创建方法
方式1
final BasicDataSource dataSource = new BasicDataSource();
	dataSource.setUsername("root");
	dataSource.setPassword("cgz12345678");
	dataSource.setUrl("jdbc:mysql://localhost:3306/testjdbc");
	dataSource.setDriverClassName("com.mysql.jdbc.Driver");
	dataSource.setInitialSize(5);
	dataSource.setMaxActive(5);
	dataSource.setMinIdle(2);
	dataSource.setMaxWait(1000*5);
方式2
    Properties properties = new Properties();
	InputStream stream = jdbctestc3p0_dbcp.class.getClassLoader().getResourceAsStream("2.properties");
	try {
		properties.load(stream);
		DataSource dataSource = 
				BasicDataSourceFactory.createDataSource(properties);
		BasicDataSource source =(BasicDataSource)dataSource;
	} catch (Exception e) {
		e.printStackTrace();
	}
Properties文件
driverClassName=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/testjdbc
username=root
password=cgz12345678

DBCP 是单线程的,为了保证线程安全会锁整个连接池
DBCP 性能不佳
DBCP 太复杂,超过60个类,发展滞后
还有其它的高性能连接池,如C3P0,还有阿里系的druid等

3)DRUID

API官方文档https://github.com/alibaba/druid/wiki/DruidDataSource%E9%85%8D%E7%BD%AE    

#驱动类名。
driverClassName=com.mysql.jdbc.Driver
#连接数据库的url
url=jdbc:mysql://127.0.0.1:3306/day25
#数据库的用户名
username=root
#数据库的密码
password=12345678
#初始化时建立物理连接的个数。初始化发生在显示调用init方法,或者第一次getConnection时
initialSize=5
#最大连接池数量
maxActive=10
#获取连接时最大等待时间
maxWait=3000
#已经不再使用,配置了也没效果
maxIdle=6
#最小连接池数量
minIdle=3
// 加载配置文件中的配置参数
InputStream is = Demo03.class.getResourceAsStream("/druid.properties");
Properties pp = new Properties();
pp.load(is);
// 创建连接池,使用配置文件中的参数
DataSource ds = DruidDataSourceFactory.createDataSource(pp);

 备注:连接池超标报异常

4)自定义线程池

package cn.test.javamail.massage;

import org.springframework.jdbc.datasource.DataSourceTransactionManager;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import sun.applet.Main;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.sql.SQLFeatureNotSupportedException;
import java.util.LinkedList;
import java.util.List;
import java.util.Properties;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.logging.Logger;

public  class MyDataSourcePool  implements DataSource {
    private int initCount ;
    private int maxCount ;
    private int curCount  ;

    private List<Connection>  list=  new LinkedList();

    public MyDataSourcePool(int initCount, int maxCount) throws SQLException, IOException, ClassNotFoundException {
        this.initCount = initCount;
        this.maxCount = maxCount;
        for (int i = 0; i < initCount; i++) {
            Connection connect = getConnect();
            list.add(connect);
            curCount++;
        }
    }

    @Override
    public Connection getConnection() throws SQLException {
        Connection connection=null;
        if(list.size()>0){
            connection = list.get(0);
            list.remove(0);
        }else  if(curCount<maxCount){
            try {
                Connection connect = getConnect();//不足的时候每次创建一个
                list.add(connect);
                curCount++;
                connection = list.get(0);
                list.remove(0);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }else{
            new RuntimeException("已经满了");
        }
        return connection;
    }

    public  void close(Connection connect){//c3p0的close重写内部的方法
        list.add(connect);
    }
    @Override
    public Connection getConnection(String username, String password) throws SQLException {
        return null;
    }

    @Override
    public <T> T unwrap(Class<T> iface) throws SQLException {
        return null;
    }

    @Override
    public boolean isWrapperFor(Class<?> iface) throws SQLException {
        return false;
    }

    @Override
    public PrintWriter getLogWriter() throws SQLException {
        return null;
    }

    @Override
    public void setLogWriter(PrintWriter out) throws SQLException {

    }

    @Override
    public void setLoginTimeout(int seconds) throws SQLException {

    }

    @Override
    public int getLoginTimeout() throws SQLException {
        return 0;
    }

    @Override
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {
        return null;
    }

    public  Connection  getConnect() throws IOException, ClassNotFoundException, SQLException {
        Properties ps = new Properties();
        InputStream is = this.getClass().getClassLoader().getResourceAsStream("config.properties");
        ps.load(is);
        Class.forName(ps.getProperty("driverClass"));
        Connection connection = DriverManager.getConnection(ps.getProperty("url"), ps);
        return connection;
    }

}
原文地址:https://www.cnblogs.com/gg128/p/9788105.html