JDBC连接池
一、连接池基本概念
1. 什么是连接池
连接池是创建和管理数据库连接的缓冲池技术,它预先建立一定数量的数据库连接,当应用程序需要时从池中获取连接,使用完毕后归还给池而不是直接关闭。
2. 为什么需要连接池
- 资源重用:避免频繁创建和销毁连接的开销
- 性能提升:减少连接建立时间,提高响应速度
- 连接管理:统一管理连接,避免连接泄漏
- 系统稳定:控制最大连接数,防止数据库过载
二、主流JDBC连接池
1. HikariCP
特点:
- 目前性能最好的连接池
- 代码精简(约130kb)
- 零依赖
- 支持JMX监控
Maven依赖:
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version>
</dependency>
2. Druid
特点:
- 阿里巴巴开源项目
- 功能全面(监控、加密等)
- 对MySQL特别优化
- 提供强大的监控统计功能
Maven依赖:
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version>
</dependency>
3. Apache DBCP2
特点:
- Apache Commons项目
- 成熟稳定
- 功能全面
- 适合传统企业应用
Maven依赖:
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
<version>2.9.0</version>
</dependency>
4. C3P0
特点:
- 老牌连接池
- 稳定性好
- 支持JDBC3和JDBC2
- 配置相对复杂
Maven依赖:
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
三、连接池配置详解
1. 核心配置参数
参数 | 说明 | 推荐值 |
---|---|---|
initialSize | 初始连接数 | 5-10 |
minIdle | 最小空闲连接 | 与initialSize相同 |
maxActive/maximumPoolSize | 最大活动连接数 | 20-100(根据系统负载调整) |
maxWait | 获取连接最大等待时间(ms) | 3000 |
timeBetweenEvictionRunsMillis | 检查空闲连接的间隔时间(ms) | 60000 |
minEvictableIdleTimeMillis | 连接最小空闲时间(ms) | 300000 |
validationQuery | 连接有效性测试SQL | SELECT 1 |
testWhileIdle | 空闲时是否测试连接 | true |
testOnBorrow | 获取连接时是否测试 | false |
testOnReturn | 归还连接时是否测试 | false |
2. HikariCP配置示例
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
config.setUsername("username");
config.setPassword("password");
config.setDriverClassName("com.mysql.jdbc.Driver");
// 连接池配置
config.setMaximumPoolSize(20);
config.setMinimumIdle(5);
config.setConnectionTimeout(3000);
config.setIdleTimeout(60000);
config.setMaxLifetime(1800000);
config.setPoolName("MyHikariCP");
// MySQL优化参数
config.addDataSourceProperty("cachePrepStmts", "true");
config.addDataSourceProperty("prepStmtCacheSize", "250");
config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048");
HikariDataSource dataSource = new HikariDataSource(config);
3. Druid配置示例
DruidDataSource dataSource = new DruidDataSource();
// 基本配置
dataSource.setUrl("jdbc:mysql://localhost:3306/mydb");
dataSource.setUsername("username");
dataSource.setPassword("password");
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
// 连接池配置
dataSource.setInitialSize(5);
dataSource.setMinIdle(5);
dataSource.setMaxActive(20);
dataSource.setMaxWait(3000);
dataSource.setTimeBetweenEvictionRunsMillis(60000);
dataSource.setMinEvictableIdleTimeMillis(300000);
// 监控配置
dataSource.setFilters("stat,wall");
dataSource.setUseGlobalDataSourceStat(true);
// 连接测试
dataSource.setValidationQuery("SELECT 1");
dataSource.setTestWhileIdle(true);
dataSource.setTestOnBorrow(false);
dataSource.setTestOnReturn(false);
四、连接池使用模式
1. 基本使用模式
// 获取数据源
DataSource dataSource = getDataSource();
try (Connection conn = dataSource.getConnection();
PreparedStatement pstmt = conn.prepareStatement("SELECT * FROM users");
ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
// 处理结果
}
} catch (SQLException e) {
// 异常处理
}
2. 使用连接池的工具类
public class JdbcUtils {
private static DataSource dataSource;
static {
// 初始化连接池
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
// 其他配置...
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void close(Connection conn, Statement stmt, ResultSet rs) {
try {
if (rs != null) rs.close();
if (stmt != null) stmt.close();
if (conn != null) conn.close(); // 实际是归还给连接池
} catch (SQLException e) {
// 日志记录
}
}
}
3. 与Spring集成
@Configuration
public class DataSourceConfig {
@Bean
public DataSource dataSource() {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/mydb");
// 其他配置...
return new HikariDataSource(config);
}
@Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
五、连接池监控与管理
1. HikariCP监控
HikariDataSource dataSource = (HikariDataSource) context.getBean("dataSource");
// 获取连接池状态
HikariPoolMXBean poolMXBean = dataSource.getHikariPoolMXBean();
System.out.println("活动连接: " + poolMXBean.getActiveConnections());
System.out.println("空闲连接: " + poolMXBean.getIdleConnections());
System.out.println("等待线程: " + poolMXBean.getThreadsAwaitingConnection());
2. Druid监控
// 配置Web监控
@Bean
public ServletRegistrationBean<StatViewServlet> druidStatViewServlet() {
ServletRegistrationBean<StatViewServlet> reg = new ServletRegistrationBean<>();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
// 白名单
reg.addInitParameter("allow", "127.0.0.1");
// 黑名单
reg.addInitParameter("deny", "");
// 登录查看信息的账号密码
reg.addInitParameter("loginUsername", "admin");
reg.addInitParameter("loginPassword", "admin");
return reg;
}
// 配置过滤器
@Bean
public FilterRegistrationBean<WebStatFilter> druidWebStatFilter() {
FilterRegistrationBean<WebStatFilter> reg = new FilterRegistrationBean<>();
reg.setFilter(new WebStatFilter());
reg.addUrlPatterns("/*");
reg.addInitParameter("exclusions", "*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
return reg;
}
六、连接池最佳实践
-
选择合适的连接池:新项目推荐HikariCP,需要监控选Druid
-
合理配置连接数:
- 计算公式:连接数 = (核心数 * 2) + 有效磁盘数
- 对于8核系统:建议连接数在20-30之间
-
连接泄漏检测:
// HikariCP config.setLeakDetectionThreshold(60000); // 60秒 // Druid dataSource.setRemoveAbandoned(true); dataSource.setRemoveAbandonedTimeout(60); // 60秒 dataSource.setLogAbandoned(true);
-
生产环境建议:
- 开启连接池JMX监控
- 定期检查连接池状态
- 设置合理的超时时间
- 配置连接有效性测试
-
避免常见错误:
- 忘记关闭连接(使用try-with-resources)
- 在循环中创建连接池
- 配置过大的maxActive值
- 不配置validationQuery
七、连接池性能优化
-
预处理语句缓存:
// HikariCP config.addDataSourceProperty("cachePrepStmts", "true"); config.addDataSourceProperty("prepStmtCacheSize", "250"); config.addDataSourceProperty("prepStmtCacheSqlLimit", "2048"); // Druid dataSource.setPoolPreparedStatements(true); dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
-
连接超时设置:
- connectionTimeout:获取连接超时(推荐1-5秒)
- idleTimeout:空闲连接超时(推荐60秒)
- maxLifetime:连接最大生命周期(推荐30分钟)
-
JDBC驱动参数优化:
// MySQL config.addDataSourceProperty("useServerPrepStmts", "true"); config.addDataSourceProperty("useLocalSessionState", "true"); config.addDataSourceProperty("rewriteBatchedStatements", "true"); config.addDataSourceProperty("cacheResultSetMetadata", "true"); config.addDataSourceProperty("cacheServerConfiguration", "true"); config.addDataSourceProperty("elideSetAutoCommits", "true"); config.addDataSourceProperty("maintainTimeStats", "false");