Java连接池性能检测:如何对比不同连接池的性能差异
Java连接池性能检测方案与代码
为什么单线程循环测不出差异
单线程下,连接池的连接复用、并发控制优势无法体现,所有操作串行执行,耗时差异被完全抹平。要测出真实性能差异,必须模拟高并发场景,同时聚焦以下核心指标:
- 连接获取的平均/峰值耗时
- 并发吞吐量(每秒处理的连接请求数)
- 连接池资源耗尽时的等待/拒绝表现
- 连接归还后的复用效率
通用检测框架代码
下面使用JMH(Java官方推荐的微基准测试工具)来实现,它能规避JIT优化、测量误差等问题,同时模拟多线程并发场景,对比HikariCP、Apache Commons DBCP2、Tomcat JDBC Pool这几款主流连接池。
1. Maven依赖配置
<dependencies> <!-- JMH核心依赖 --> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-core</artifactId> <version>1.37</version> </dependency> <dependency> <groupId>org.openjdk.jmh</groupId> <artifactId>jmh-generator-annprocess</artifactId> <version>1.37</version> <scope>provided</scope> </dependency> <!-- 各连接池依赖 --> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <version>5.0.1</version> </dependency> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-dbcp2</artifactId> <version>2.10.0</version> </dependency> <dependency> <groupId>org.apache.tomcat</groupId> <artifactId>tomcat-jdbc</artifactId> <version>10.1.15</version> </dependency> <!-- H2内存数据库,排除真实DB的IO干扰 --> <dependency> <groupId>com.h2database</groupId> <artifactId>h2</artifactId> <version>2.2.224</version> </dependency> </dependencies>
2. 基准测试代码
import org.openjdk.jmh.annotations.*; import org.openjdk.jmh.runner.Runner; import org.openjdk.jmh.runner.RunnerException; import org.openjdk.jmh.runner.options.Options; import org.openjdk.jmh.runner.options.OptionsBuilder; import javax.sql.DataSource; import java.sql.Connection; import java.sql.SQLException; import java.util.concurrent.TimeUnit; @BenchmarkMode(Mode.Throughput) @OutputTimeUnit(TimeUnit.SECONDS) @State(Scope.Benchmark) @Fork(1) @Warmup(iterations = 3, time = 5) @Measurement(iterations = 5, time = 10) public class ConnectionPoolBenchmark { private DataSource hikariDs; private DataSource dbcp2Ds; private DataSource tomcatDs; @Setup(Level.Trial) public void setup() { // 初始化HikariCP com.zaxxer.hikari.HikariConfig hikariConfig = new com.zaxxer.hikari.HikariConfig(); hikariConfig.setJdbcUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); hikariConfig.setUsername("sa"); hikariConfig.setPassword(""); hikariConfig.setMaximumPoolSize(20); hikariDs = new com.zaxxer.hikari.HikariDataSource(hikariConfig); // 初始化DBCP2 org.apache.commons.dbcp2.BasicDataSource dbcp2Config = new org.apache.commons.dbcp2.BasicDataSource(); dbcp2Config.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); dbcp2Config.setUsername("sa"); dbcp2Config.setPassword(""); dbcp2Config.setMaxTotal(20); dbcp2Ds = dbcp2Config; // 初始化Tomcat JDBC Pool org.apache.tomcat.jdbc.pool.DataSource tomcatConfig = new org.apache.tomcat.jdbc.pool.DataSource(); tomcatConfig.setUrl("jdbc:h2:mem:test;DB_CLOSE_DELAY=-1"); tomcatConfig.setUsername("sa"); tomcatConfig.setPassword(""); tomcatConfig.setMaxActive(20); tomcatDs = tomcatConfig; } @TearDown(Level.Trial) public void tearDown() throws SQLException { ((com.zaxxer.hikari.HikariDataSource) hikariDs).close(); ((org.apache.commons.dbcp2.BasicDataSource) dbcp2Ds).close(); ((org.apache.tomcat.jdbc.pool.DataSource) tomcatDs).close(); } @Benchmark @Threads(20) // 并发线程数与连接池最大容量一致,模拟满负载场景 public void testHikariCP() throws SQLException { try (Connection conn = hikariDs.getConnection()) { // 执行简单查询,避免连接操作被JIT优化 conn.createStatement().execute("SELECT 1"); } } @Benchmark @Threads(20) public void testDBCP2() throws SQLException { try (Connection conn = dbcp2Ds.getConnection()) { conn.createStatement().execute("SELECT 1"); } } @Benchmark @Threads(20) public void testTomcatJDBC() throws SQLException { try (Connection conn = tomcatDs.getConnection()) { conn.createStatement().execute("SELECT 1"); } } public static void main(String[] args) throws RunnerException { Options options = new OptionsBuilder() .include(ConnectionPoolBenchmark.class.getSimpleName()) .build(); new Runner(options).run(); } }
测试关键说明
- 选择JMH而非手动循环:JMH会自动处理JIT预热、线程同步、测量误差等问题,测试结果更可靠。
- 模拟满负载并发:设置线程数与连接池最大容量一致,此时不同连接池的调度效率差异会被放大。
- 添加真实DB操作:单纯的连接获取/归还可能被JIT优化,加上简单查询能更贴近业务实际场景。
- 使用内存数据库:H2内存DB避免了真实数据库的网络、磁盘IO干扰,聚焦连接池本身的性能表现。
扩展测试维度
如果需要更全面的性能分析,还可以:
- 测试连接池耗尽场景:设置线程数远大于连接池最大容量,测量等待超时时间、拒绝请求比例。
- 测试连接泄漏检测:模拟连接未归还的情况,观察不同连接池的泄漏告警、自动回收机制效率。
- 测试长时间运行稳定性:让测试持续数小时,监控连接池的内存占用、连接存活状态。
内容的提问来源于stack exchange,提问作者chandrahas g
相关产品推荐
相关产品推荐

