为什么需要数据库连接池?
在传统的 JDBC 编程中,每次执行 SQL 语句都需要经历以下步骤:

- 加载驱动
- 建立连接 (
DriverManager.getConnection()) - 执行 SQL
- 关闭连接
这个过程非常耗时,尤其是建立连接,如果高并发场景下,大量用户同时请求,频繁地创建和销毁连接会导致:
- 性能低下:连接创建和销毁的开销巨大。
- 资源浪费:数据库能同时处理的连接数是有限的,大量连接请求会耗尽数据库资源,导致系统崩溃。
数据库连接池 就是为了解决这个问题而生的,它像一个“连接仓库”,在应用启动时就预先创建好一批数据库连接,并将它们存放在池中,当需要执行 SQL 时,直接从池中获取一个可用连接,用完后再归还给池,而不是销毁,这样就避免了频繁创建和销毁连接的开销,极大地提升了性能。
主流 Java 数据库连接池
目前最主流、性能最优的连接池是 HikariCP,还有一些经典的选择,如 Druid 和 C3P0。
| 连接池 | 特点 | 推荐度 |
|---|---|---|
| HikariCP | 性能极高,代码简洁,稳定可靠,是目前事实上的标准。 | ⭐⭐⭐⭐⭐ (首选) |
| Druid | 性能优秀,功能强大,自带监控、统计、防 SQL 注入等功能。 | ⭐⭐⭐⭐ (功能首选) |
| C3P0 | 老牌连接池,稳定,但性能相对 HikariCP 和 Druid 稍差。 | ⭐⭐ (不推荐新项目) |
下面我们将重点介绍 HikariCP 和 Druid 的使用方法。

准备工作:添加 MySQL 驱动依赖
无论使用哪个连接池,你都需要先添加 MySQL 的 JDBC 驱动依赖,如果你的项目使用 Maven,在 pom.xml 中添加以下依赖:
<!-- MySQL JDBC 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version> <!-- 建议使用较新版本 -->
</dependency>
使用 HikariCP (推荐)
HikariCP 的配置非常简单,性能极佳。
添加 HikariCP 依赖
在 pom.xml 中添加:
<!-- HikariCP 连接池 -->
<dependency>
<groupId>com.zaxxer</groupId>
<artifactId>HikariCP</artifactId>
<version>5.0.1</version> <!-- 建议使用较新版本 -->
</dependency>
创建 HikariConfig 配置对象并初始化连接池
HikariCP 提供了两种配置方式:Java 代码配置和配置文件(如 properties 或 yml),推荐使用配置文件,更易于管理。

使用 properties 文件
-
在
src/main/resources目录下创建db.properties文件:# 数据库连接信息 jdbcUrl=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 username=root password=your_password # 连接池配置 # 最小空闲连接数 minimum-idle=5 # 连接池最大连接数 maximum-pool-size=15 # 连接在池中最大存活时间,0表示永久存活 max-lifetime=1800000 # 30分钟 # 空闲连接最大存活时间,0表示永不丢弃 idle-timeout=600000 # 10分钟
-
在 Java 代码中加载配置并创建连接池:
import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import java.sql.Connection; import java.sql.SQLException; import java.io.InputStream; import java.util.Properties; public class HikariCPUtil { private static HikariDataSource dataSource; static { try (InputStream is = HikariCPUtil.class.getClassLoader().getResourceAsStream("db.properties")) { Properties props = new Properties(); props.load(is); HikariConfig config = new HikariConfig(); config.setJdbcUrl(props.getProperty("jdbcUrl")); config.setUsername(props.getProperty("username")); config.setPassword(props.getProperty("password")); config.setMinimumIdle(Integer.parseInt(props.getProperty("minimum-idle"))); config.setMaximumPoolSize(Integer.parseInt(props.getProperty("maximum-pool-size"))); config.setMaxLifetime(Long.parseLong(props.getProperty("max-lifetime"))); config.setIdleTimeout(Long.parseLong(props.getProperty("idle-timeout"))); dataSource = new HikariDataSource(config); } catch (Exception e) { throw new RuntimeException("Failed to initialize HikariCP connection pool", e); } } // 获取连接 public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } // 关闭连接池 (通常在应用关闭时调用) public static void closeDataSource() { if (dataSource != null && !dataSource.isClosed()) { dataSource.close(); } } }
纯 Java 代码配置
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class HikariCPUtil_Code {
private static HikariDataSource dataSource;
static {
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC&characterEncoding=utf8");
config.setUsername("root");
config.setPassword("your_password");
config.setMinimumIdle(5);
config.setMaximumPoolSize(15);
config.setMaxLifetime(1800000);
config.setIdleTimeout(600000);
dataSource = new HikariDataSource(config);
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
}
使用连接池进行数据库操作
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class UserDao {
public String findUserNameById(int id) {
String sql = "SELECT username FROM users WHERE id = ?";
Connection connection = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
String username = null;
try {
// 1. 从连接池获取连接
connection = HikariCPUtil.getConnection();
// 2. 创建 PreparedStatement
pstmt = connection.prepareStatement(sql);
pstmt.setInt(1, id);
// 3. 执行查询
rs = pstmt.executeQuery();
if (rs.next()) {
username = rs.getString("username");
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 4. 关闭资源 (非常重要!)
// 注意:这里不是关闭连接,而是将连接归还给连接池
try {
if (rs != null) rs.close();
if (pstmt != null) pstmt.close();
// connection.close(); // 千万不要调用这个!
} catch (SQLException e) {
e.printStackTrace();
}
}
return username;
}
}
使用 Druid
Druid 由阿里巴巴开源,除了高性能外,还提供了强大的监控功能。
添加 Druid 依赖
在 pom.xml 中添加:
<!-- Druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.16</version> <!-- 建议使用较新版本 -->
</dependency>
创建 DruidDataSource 配置并初始化连接池
同样,推荐使用配置文件。
-
在
src/main/resources目录下创建db.properties文件:# 数据库连接信息 jdbcUrl=jdbc:mysql://localhost:3306/your_database?useSSL=false&serverTimezone=UTC&characterEncoding=utf8 username=root password=your_password # 连接池配置 initialSize=5 minIdle=5 maxActive=15 maxWait=60000 timeBetweenEvictionRunsMillis=60000 minEvictableIdleTimeMillis=300000 validationQuery=SELECT 1 testWhileIdle=true testOnBorrow=false testOnReturn=false poolPreparedStatements=true maxPoolPreparedStatementPerConnectionSize=20
-
在 Java 代码中加载配置并创建连接池:
import com.alibaba.druid.pool.DruidDataSource; import com.alibaba.druid.pool.DruidDataSourceFactory; import javax.sql.DataSource; import java.io.InputStream; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; public class DruidUtil { private static DataSource dataSource; static { try (InputStream is = DruidUtil.class.getClassLoader().getResourceAsStream("db.properties")) { Properties props = new Properties(); props.load(is); dataSource = DruidDataSourceFactory.createDataSource(props); } catch (Exception e) { throw new RuntimeException("Failed to initialize Druid connection pool", e); } } public static Connection getConnection() throws SQLException { return dataSource.getConnection(); } public static DataSource getDataSource() { return dataSource; } public static void closeDataSource() { if (dataSource instanceof DruidDataSource) { ((DruidDataSource) dataSource).close(); } } }
使用 Druid 的监控功能 (Druid 的特色)
Druid 提供了一个内置的监控页面,非常方便查看 SQL 执行情况、连接池状态等。
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import javax.servlet.annotation.WebFilter;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
// 如果使用 Spring Boot,通常通过配置类来注册 Servlet 和 Filter
// 如果是原生 Servlet 项目,可以这样配置
// 监控页面 Servlet
@WebServlet(urlPatterns = "/druid/*", name = "druidStatViewServlet")
public class DruidStatViewServlet extends StatViewServlet {
// ... 省略
}
// 监控 Filter
@WebFilter(urlPatterns = "/*", filterName = "druidWebStatFilter")
public class DruidWebStatFilter extends WebStatFilter {
// ... 省略
}
访问 http://yourserver:port/your-app/druid/index.html 即可看到监控页面。
最佳实践与总结
- 选择 HikariCP:对于绝大多数新项目,HikariCP 是首选,它的性能是业界标杆,配置简单,稳定可靠。
- 单例模式:连接池对象应该是全局唯一的,通常使用静态变量和静态代码块来初始化。
- 资源管理:
Connection,PreparedStatement,ResultSet等资源必须在使用后关闭,最好在finally块中关闭。切记不要调用connection.close()来关闭连接,而是要关闭Statement和ResultSet,连接会自动归还给池。 - 配置调优:
maximum-pool-size(最大连接数) 和minimum-idle(最小空闲连接数) 是最重要的两个参数,需要根据你的应用并发量和数据库服务器的承受能力来调整,一个经验法则是:maximum-pool-size=(核心数 * 2) + 有效磁盘数。 - 整合 Spring/Spring Boot:在实际开发中,我们很少手动创建连接池,通常使用 Spring 或 Spring Boot 框架,它们会自动配置和管理连接池,你只需要在
application.properties或application.yml文件中配置连接信息即可,框架会自动为你创建并注入DataSourcebean。
在 Spring Boot 中,你只需要配置:
# application.properties spring.datasource.url=jdbc:mysql://localhost:3306/your_db spring.datasource.username=root spring.datasource.password=your_password spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver # Spring Boot 2.x 默认使用 HikariCP # 可以通过 spring.datasource.type 指定为其他连接池,如 com.alibaba.druid.pool.DruidDataSource
Spring Boot 会自动根据这些属性创建一个 HikariCP 连接池,并将其注入到需要 @Autowired DataSource dataSource; 的地方,这是最推荐、最简单的方式。
