拓展阅读
从零开始手写 mybatis (三)jdbc pool 如何从零手写实现数据库连接池 dbcp?
万字长文深入浅出数据库连接池 HikariCP/Commons DBCP/Tomcat/c3p0/druid 对比
Database Connection Pool 数据库连接池概览
Apache Tomcat DBCP(Database Connection Pool) 数据库连接池-01-入门介绍
vibur-dbcp 并发、快速且功能完备的 JDBC 连接池,提供先进的性能监控功能-01-入门介绍
Vibur DBCP
Vibur DBCP 是一个并发、快速且功能完备的 JDBC 连接池,提供先进的性能监控功能,包括慢 SQL 查询的检测和记录、应用线程的非饥饿保证、语句缓存以及与 Hibernate 集成等特性。
该项目主页包含了对所有 Vibur 特性和配置选项的详细描述,以及与 Hibernate 和 Spring 的各种配置示例等内容。
Vibur DBCP 基于 Vibur Object Pool 构建,后者是一个通用的并发 Java 对象池。
介绍
Vibur 是一个使用标准 Java 并发工具完全构建的 JDBC 连接池库。它具有简洁和简单的源代码基础以及模块化设计,包括一个独立的专用对象池。
在底层,它依赖于一个简单而健壮的连接池机制,该机制是在一个由信号量保护的队列之上实现的。
Vibur DBCP 使用 Java 动态代理来创建实现 JDBC API 接口的对象。这些代理是 Java 自 1.3 版本以来存在的强大工具,不依赖于任何第三方字节码操作库,如 Javassist 或 cglib。
动态代理允许 Vibur 选择需要实现的 JDBC 接口的方法。例如,Vibur DBCP 提供的主要 JDBC 接口共有约 480 个方法;然而,少于 100 个方法的调用被明确拦截和处理,所有其他方法调用都简单地转发到它们的默认实现。这大大减少了 Vibur 需要提供所有被代理的 JDBC API 接口的静态实现所需的样板代码量。
除了通常的 JDBC 连接池功能之外,Vibur DBCP 还提供了几个高级功能,可帮助识别复杂问题并回答诸如"为什么"和"在哪里"等问题,这些问题发生在具有大量运行部件的生产系统上。
主要特点一览
- 确保没有线程会被排除在访问 JDBC 连接池连接之外。参见 poolFair 配置参数。
- 检测和记录慢 SQL 查询、大于预期的 ResultSet 和持续时间较长的 getConnection() 方法调用。查看相关的配置属性 这里 和 这里。
- 支持 Hibernate 3.6、4.x 和 5.x 的集成。
- 对 JDBC Statement(Prepared 和 Callable)进行缓存支持。
- 使用标准 Java 并发工具和动态代理构建,不使用任何 synchronized 块或方法。
- Vibur DBCP 需要 Java 1.6+,并且仅有以下外部依赖项:其专用对象池、slf4j/log4j 和 ConcurrentLinkedHashMap。CLHM 依赖项是可选的,只有在启用/使用 JDBC Statement 缓存时,应用程序才需要提供它。
其他特点
- 智能池大小调整 - 根据最近使用的连接数量的启发式方法,可以减少 JDBC 池中的空闲连接数量。
- 支持验证间隔;即,在每次使用之前,从 JDBC 池获取的连接并不会被验证,只有在连接上一次使用后经过一定时间后才会进行验证。
- 可以通过调用代理的 unwrap 方法从相应的代理对象中检索原始 JDBC 连接或 Statement 对象。
- 为当前获取的所有 JDBC 连接提供记录(通过 JMX 或日志文件),包括它们被获取时的堆栈跟踪;如果调试丢失/未关闭的连接或者应用程序想知道当前所有连接的来源,这将非常有用。
- JMX 支持 - 池注册了一个 MBean,通过它可以观察和/或设置各种池参数。
代码度量和性能结果
下面的源代码度量不考虑项目的测试目录,以及每个源文件顶部的 Apache 许可证注释头部分。
项目 | 源文件数 | 代码行数 |
---|---|---|
Vibur DBCP | 32 | 约 4.8K |
Vibur Object Pool | 14 | 约 1.2K |
下面的性能结果是通过在具有 Intel i7-4702MQ 2.2GHz 处理器的机器上运行 Java 1.8.0_151,在 Ubuntu 16.04 上运行此测试而获得的。
该测试使用了 500 个线程,每个线程尝试从初始大小为 50,最大大小为 200 的池中进行 100 次获取/还原操作。
每个线程通过调用 Thread.sleep() 来模拟 2 或 5 毫秒的工作,并且池的公平参数设置如下表所示。执行时间是三次连续运行的平均值。
池公平性 | 模拟工作时间 | 执行时间 |
---|---|---|
true | 2 毫秒 | 955 毫秒 |
false | 2 毫秒 | 1003 毫秒 |
true | 5 毫秒 | 1714 毫秒 |
false | 5 毫秒 | 1816 毫秒 |
Maven 依赖项
Vibur 工件坐标和如何从源代码构建
xml
<dependency>
<groupId>org.vibur</groupId>
<artifactId>vibur-dbcp</artifactId>
<version>25.0</version>
</dependency>
Spring with Hibernate 3.6/4.x/5.x Configuration Snippet
xml
<!-- Vibur DBCP dataSource bean definition: -->
<bean id="dataSource" class="org.vibur.dbcp.ViburDBCPDataSource" init-method="start" destroy-method="terminate">
<property name="jdbcUrl" value="jdbc:hsqldb:mem:sakila;shutdown=false"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="poolInitialSize">10</property>
<property name="poolMaxSize">100</property>
<property name="connectionIdleLimitInSeconds">30</property>
<property name="testConnectionQuery">isValid</property>
<property name="logQueryExecutionLongerThanMs" value="500"/>
<property name="logStackTraceForLongQueryExecution" value="true"/>
<property name="statementCacheMaxSize" value="200"/>
</bean>
<!-- For Hibernate5 set the sessionFactory class below to org.springframework.orm.hibernate5.LocalSessionFactoryBean -->
<!-- For Hibernate4 set the sessionFactory class below to org.springframework.orm.hibernate4.LocalSessionFactoryBean -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan" value="the.project.packages"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
</props>
</property>
</bean>
<!-- For Hibernate5 set the transactionManager class below to org.springframework.orm.hibernate5.HibernateTransactionManager -->
<!-- For Hibernate4 set the transactionManager class below to org.springframework.orm.hibernate4.HibernateTransactionManager -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Programming Configuration Snippet
java
public DataSource createDataSourceWithStatementsCache() {
ViburDBCPDataSource ds = new ViburDBCPDataSource();
ds.setJdbcUrl("jdbc:hsqldb:mem:sakila;shutdown=false");
ds.setUsername("sa");
ds.setPassword("");
ds.setPoolInitialSize(10);
ds.setPoolMaxSize(100);
ds.setConnectionIdleLimitInSeconds(30);
ds.setTestConnectionQuery("isValid");
ds.setLogQueryExecutionLongerThanMs(500);
ds.setLogStackTraceForLongQueryExecution(true);
ds.setStatementCacheMaxSize(200);
ds.start();
return ds;
}