常用开源数据库连接池C3P0、Druid介绍

概述

很多时候,连接的混乱管理所造成的系统资源开销过大成为制约大型企业级应用效率的瓶颈。因为每一次WEB请求都要建立一次数据库连接,建立连接是一个耗费资源的活动,每次都得花费0.05-1s的时间,而且系统还要分配内存资源。

数据库连接池的基本思想就是为数据库连接建立一个“缓冲池”。于现在缓冲池中放入一定数量的连接,当需要建立数据库连接时,只需从缓冲池中取出一个,使用完毕以后再放回去即可。

C3P0

C3P0是一款优秀的开源数据库连接池,被广泛使用。

使用

maven依赖:

<dependency>
    <groupId>c3p0</groupId>
    <artifactId>c3p0</artifactId>
    <version>0.9.1.2</version>
</dependency>

基本配置:

<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
    <!-- 默认配置,如果没有指定则使用这个配置 -->
    <default-config>
        <property name="user">root</property>
        <property name="password">123456</property>
        <property name="jdbcUrl">jdbc:mysql://192.168.91.1:3306/test</property>
        <property name="driverClass">com.mysql.cj.jdbc.Driver</property>
    </default-config>
    <!-- 命名的配置,可以通过方法调用实现 -->
    <named-config name="test">
        <!-- ... -->
    </named-config>
</c3p0-config>

其他配置:

参数 默认值 解释
initialPoolSize 3 连接池初始化时创建的连接数(介于maxPoolSize和minPoolSize之间)
maxPoolSize 15 连接池中拥有的最大连接数,如果获得新连接时会使连接总数超过这个值则不会再获取新连接,而是等待其他连接释放,所以这个值有可能会设计地很大
minPoolSize 3 连接池保持的最小连接数,后面的maxIdleTimeExcessConnections跟这个配合使用来减轻连接池的负载
acquireIncrement 3 连接池在无空闲连接可用时一次性创建的新数据库连接数
maxIdleTime 0 连接的最大空闲时间,如果超过这个时间,某个数据库连接还没有被使用,则会断开掉这个连接如果为0,则永远不会断开连接
maxConnectorAge 0 连接的最大绝对年龄,单位是秒,0表示绝对年龄无限大
maxIdleTimeExcessConnection 0 单位秒,为了减轻连接池的负载,当连接池经过数据访问高峰创建了很多连接,但是后面连接池不需要维护这么多连接,必须小于maxIdleTime.配置不为0,则将连接池的数量保持到minPoolSize
automaticTestTable null 如果不为null,c3p0将生成指定名称的空表,使用该表来测试连接
connectionTesterClassName com.mchange.v2.c3p0.impl.
DefaultConnectionTester
通过实现ConnectionTester或QueryConnectionTester的类来测试连接。类名需制定全路径。
idleConnectionTestPeriod 0 每个几秒检查所有连接池中的空闲连接
preferredTestQuery null 定义所有连接测试都执行的测试语句。在使用连接测试的情况下这个一显著提高测试速度。注意: 测试的表必须在初始数据源的时候就存在
testConnectionOnCheckin FALSE 如果设为true那么在取得连接的同时将校验连接的有效性
testConnectionOnCheckout FALSE 如果为true,在连接释放的同事将校验连接的有效性。
maxStatements 0 JDBC的标准参数,用以控制数据源内加载d的PreparedStatements数量
maxStatementsPerConnection 0 maxStatementsPerConnection定义了连接池内单个连接所拥有的最大缓存statements数
statementCacheNum-
DeferredCloseThreads
0 如果大于零,则语句池将延迟物理close()缓存语句直到其父连接未被任何客户端使用,或者在其内部(例如在测试中)由池本身使用。
acquireRetryAttempts 30 定义在从数据库获取新连接失败后重复尝试的次数
acquireRetryDelay 1000 两次连接间隔时间,单位毫秒
breakAfterAcquireFailure FALSE 获取连接失败将会引起所有等待连接池来获取连接的线程抛出异常。但是数据源仍有效 保留,并在下次调用getConnection()的时候继续尝试获取连接。如果设为true,那么在尝试 获取连接失败后该数据源将申明已断开并永久关闭
autoCommitOnClose FALSE 连接关闭时默认将所有未提交的操作回滚。如果为true,则未提交设置为待提交而不是回滚。
forceIgnoreUnresolvedTransactions FALSE 官方文档建议这个不要设置为true
checkoutTimeout 0 当连接池用完时客户端调用getConnection()后等待获取新连接的时间,超时后将抛出SQLException,如设为0则无限期等待。单位毫秒。
factoryClassLocation 0 指定c3p0 libraries的路径,如果(通常都是这样)在本地即可获得那么无需设置,默认null即可
numHelperThreads 3 c3p0是异步操作的,缓慢的JDBC操作通过帮助进程完成。扩展这些操作可以有效的提升性能通过多线程实现多个操作同时被执行

使用:

DataSource dataSource = new ComboPooledDataSource();

它会自动去类路径下查找名为c3p0-config.xml配置文件并加载。

可以使用命名的配置:

DataSource dataSource = new ComboPooledDataSource("test");

使用的就是name="test"named-config

Druid

Druid是阿里开源的一个数据库连接池,借鉴了C3P0等成熟连接池的思想,具有诸多优点

使用

maven依赖:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.1.2</version>
</dependency>

基本配置:

driverClassName = com.mysql.cj.jdbc.Driver
url = jdbc:mysql://192.168.91.1:3306/test
username = root
password = 123456

其他配置:

配置 默认值 说明
initialSize 0 初始化时建立物理连接的个数。初始化发生在显式调用 init 方法,或者第一次getConnection 时
maxActive 8 最大允许的连接数
maxIdle 已过期
minIdle 最小的空闲连接数
maxWait 获取连接时最大等待时间,单位毫秒。配置了 maxWait 之后,缺省启用公平锁,并发效率会有所下降,如果需要可以通过配置 useUnfairLock 属性为 true 使用非公平锁。
validationQuery 用来检测连接是否有效的 sql,要求是一个查询语句。
testOnBorrow TRUE 申请连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能。
testOnReturn FALSE 归还连接时执行 validationQuery 检测连接是否有效,做了这个配置会降低性能
testWhileIdle FALSE 设置空闲时是否检测连接可用性。建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于 timeBetweenEvictionRunsMillis,执行 validationQuery 检测连接是否有效。
timeBetweenEvictionRunsMillis 检测需要关闭的空闲连接的间隔时间
minEvictableIdleTimeMillis 连接在池中的最小生存时间
connectionInitSqls 物理连接初始化的时候执行的sql
filters 属性类型是字符串,通过别名的方式配置扩展插件,常用的插件有: 监控统计用的filter:stat日志用的filter:log4j防御sql注入的filter:wall
proxyFilters 类型是List\<com.alibaba.druid.filter.Filter>,如果同时配置了filters和proxyFilters,是组合关系,并非替换关系

使用:

Properties properties = new Properties();
InputStream in = Demo1.class.getClassLoader().getResourceAsStream("druid.properties");
properties.load(in);
DataSource dataSource = DruidDataSourceFactory.createDataSource(properties);
//使用连接池
conn = dataSource.getConnection();

源码

public DruidPooledConnection getConnection(long maxWaitMillis) throws SQLException {
    init();

    if (filters.size() > 0) {
        FilterChainImpl filterChain = new FilterChainImpl(this);
        return filterChain.dataSource_connect(this, maxWaitMillis);
    } else {
        return getConnectionDirect(maxWaitMillis);
    }
}

DruidPooledConnection内部包装了一个Connection,增强了close等方法

@Override
public void close() throws SQLException {
    if (this.disable) {
        return;
    }

    DruidConnectionHolder holder = this.holder;
    if (holder == null) {
        if (dupCloseLogEnable) {
            LOG.error("dup close");
        }
        return;
    }

    DruidAbstractDataSource dataSource = holder.getDataSource();
    boolean isSameThread = this.getOwnerThread() == Thread.currentThread();

    if (!isSameThread) {
        dataSource.setAsyncCloseConnectionEnable(true);
    }

    if (dataSource.isAsyncCloseConnectionEnable()) {
        syncClose();
        return;
    }

    for (ConnectionEventListener listener : holder.getConnectionEventListeners()) {
        listener.connectionClosed(new ConnectionEvent(this));
    }


    List<Filter> filters = dataSource.getProxyFilters();
    if (filters.size() > 0) {
        FilterChainImpl filterChain = new FilterChainImpl(dataSource);
        filterChain.dataSource_recycle(this);
    } else {
        recycle();
    }

    this.disable = true;
}

【附】了解:DBUtils的使用

QueryRunner、DbUtils、ResultSetHandler。

原创文章,作者:彭晨涛,如若转载,请注明出处:https://www.codetool.top/article/%e5%b8%b8%e7%94%a8%e5%bc%80%e6%ba%90%e6%95%b0%e6%8d%ae%e5%ba%93%e8%bf%9e%e6%8e%a5%e6%b1%a0c3p0%e3%80%81druid%e4%bb%8b%e7%bb%8d/

(0)
彭晨涛彭晨涛管理者
上一篇 2020年3月4日 01:23
下一篇 2020年3月4日 20:44

相关推荐

  • Java线程池详解

    线程池就是享元模式和生产者消费者模式的应用 动手实现线程池 步骤1:自定义拒绝策略接口 @FunctionalInterface // 拒绝策略 interface RejectP…

    2020年2月3日
    0310
  • CopyOnWriteArrayList源码分析

    总结 总结放前面防止太长不看 CopyOnWriteArrayList是一个线程安全、并且在读操作时无锁的List实现。 CopyOnWriteArrayList内部通过volat…

    Java 2020年2月15日
    0200
  • CountDownLatch及CyclicBarrier源码分析

    之前写的一篇博客JUC包下的线程协作计数CountDownLatch及CyclicBarrier只是介绍了一下这两个工具类的用法,并没有深入探究源码,然而实现方法也比较简单,所以合…

    Java 2020年5月22日
    0140
  • Java基础查缺补漏05

    继续我的复习刷题 可以有和类名同名的函数 题目: JAVA中,下列语句哪一个正确() A. class中的constructor不可省略B. constructor必须与class…

    Java 2020年5月29日
    0140
  • Java基础查缺补漏04

    继续我的复习刷题 接口方法可以使用abstract修饰 问题: java接口的方法修饰符可以为?(忽略内部接口) A. privateB. protectedC. finalD. …

    Java 2020年5月28日
    0200
  • 谈谈Java中的Iterator

    摘要 Iterator的作用? Iterator和Enumeration的区别? Iterator和ListIterator的区别? Iterator和foreach的关联? It…

    Java 2019年12月6日
    0180
  • MySQL索引概述及索引的分类

    概述 MySQL官方对索引的定义为:索引(index)是帮助MySQL高效获取数据的数据结构(有序)。在数据之外,数据库系统还维护者满足特定查找算法的数据结构,这些数据结构以某种方…

    2020年3月4日
    0290
  • 深入理解java虚拟机第三版读书笔记09

    续深入理解java虚拟机第三版读书笔记08 类加载器 通过一个类的全限定名来获取描述该类的二进制字节流称为类加载器。类加载器可以用户自定义,是java语言流行的一项原因 类与类加载…

    2020年1月23日
    0130
  • JDK8新增高效原子累加器LongAdder源码分析

    很久以前写过CAS应用之JUC下的原子类,但是LongAdder这个类没有去看,只是给了一个其他博客的参考链接。今天就自己来分析一下。 AtomicLong的问题和LongAdde…

    2020年5月19日
    0740
  • HashSet源码分析

    Set家族一览: HashSet简介 Set是Collection三大接口其中之一,意为集合,且元素不能重复。Set接口中的方法和Collection中的方法完全一致,只是起到一个…

    2019年12月2日
    0200

发表回复

登录后才能评论