什么是数据库连接池?
数据库连接池(Database Connection Pool)是一种用于管理和复用数据库连接的技术,旨在提高数据库操作的性能和资源利用率。
为什么需要连接池?
每次应用程序与数据库建立连接时,都需要进行以下操作:
建立网络连接
用户身份验证
分配数据库资源
这些操作开销较大,尤其在高并发场景下,频繁地创建和关闭连接会显著影响系统性能。
连接池的工作原理
数据库连接池在应用程序启动时预先创建一定数量的数据库连接,并将这些连接保存在一个“池子”中。当应用程序需要访问数据库时:
从池中获取连接:而不是新建连接。
使用连接执行SQL操作。
使用完毕后归还连接:连接不会被关闭,而是返回连接池,供后续请求复用。
CP30
添加依赖(Maven)
在 pom.xml
中添加 C3P0 和数据库驱动(以 MySQL 为例):
<dependencies>
<!-- C3P0 连接池 -->
<dependency>
<groupId>com.mchange</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.5.5</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
配置 C3P0 连接池
C3P0 支持多种配置方式:代码配置、配置文件配置(c3p0-config.xml
)、修改application.yml配置文件。
方式一:代码方式配置
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0Example {
// 创建数据源(连接池)
private static ComboPooledDataSource dataSource;
static {
dataSource = new ComboPooledDataSource();
try {
// 数据库连接信息
dataSource.setDriverClass("com.mysql.cj.jdbc.Driver");
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC");
dataSource.setUser("root");
dataSource.setPassword("123456");
// 连接池参数配置
dataSource.setInitialPoolSize(5); // 初始连接数
dataSource.setMinPoolSize(5); // 最小空闲连接
dataSource.setMaxPoolSize(20); // 最大连接数
dataSource.setMaxIdleTime(3000); // 连接最大空闲时间(秒)
dataSource.setAcquireIncrement(5); // 获取连接时增加的连接数
dataSource.setMaxStatements(50); // 开启 PreparedStatement 缓存
dataSource.setIdleConnectionTestPeriod(60); // 每隔60秒检查空闲连接
dataSource.setTestConnectionOnCheckin(true); // 检查归还的连接是否有效
dataSource.setTestConnectionOnCheckout(false); // 获取连接时不检查(影响性能)
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 关闭连接(归还到池中)
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close(); // 实际上是归还,不是关闭
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 测试连接
public static void main(String[] args) {
try (Connection conn = getConnection()) {
System.out.println("数据库连接成功!");
System.out.println("连接对象: " + conn);
} catch (SQLException e) {
System.err.println("连接失败: " + e.getMessage());
}
}
}
方式二:使用 c3p0-config.xml
配置文件
在 src/main/resources
目录下创建文件:c3p0-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<c3p0-config>
<!-- 默认配置 -->
<default-config>
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC</property>
<property name="user">root</property>
<property name="password">123456</property>
<property name="initialPoolSize">5</property>
<property name="minPoolSize">5</property>
<property name="maxPoolSize">20</property>
<property name="acquireIncrement">5</property>
<property name="maxIdleTime">3000</property>
<property name="maxStatements">50</property>
<property name="idleConnectionTestPeriod">60</property>
<property name="testConnectionOnCheckin">true</property>
<property name="testConnectionOnCheckout">false</property>
</default-config>
<!-- 命名配置(可选,用于不同数据源) -->
<named-config name="production">
<property name="driverClass">com.mysql.cj.jdbc.Driver</property>
<property name="jdbcUrl">jdbc:mysql://prod-db:3306/appdb?useSSL=false&serverTimezone=UTC</property>
<property name="user">prod_user</property>
<property name="password">prod_pass</property>
<property name="maxPoolSize">50</property>
<property name="acquireIncrement">10</property>
</named-config>
</c3p0-config>
使用配置文件创建数据源
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class C3P0WithConfigFile {
private static ComboPooledDataSource dataSource;
static {
// 使用默认配置
dataSource = new ComboPooledDataSource();
// 或使用命名配置
// dataSource = new ComboPooledDataSource("production");
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void main(String[] args) {
try (Connection conn = getConnection()) {
System.out.println("通过配置文件连接成功!");
System.out.println("连接: " + conn);
} catch (SQLException e) {
e.printStackTrace();
}
}
}
方法三:修改application.yml配置文件
c3p0: # 定义C3P0配置
jdbcUrl: jdbc:mysql://localhost:3306/mldn # 数据库连接地址
user: root # 数据库用户名
password: mysqladmin # 数据库密码
driverClass: org.gjt.mm.mysql.Driver # 数据库驱动程序
minPoolSize: 1 # 最小连接数
maxPoolSize: 1 # 最大连接数
maxIdleTime: 3000 # 最大等待时间
initialPoolSize: 1 # 初始化连接数
如何通过 C3P0 获取数据库连接并进行基本操作:
获取连接:通过
dataSource.getConnection()
获取数据库连接。执行 SQL:使用
PreparedStatement
执行查询,并处理结果集。资源管理:通过
finally
块确保ResultSet
、PreparedStatement
和Connection
被正确关闭(实际是归还到连接池)。
import com.mchange.v2.c3p0.ComboPooledDataSource;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
public class C3P0Example {
// 创建数据源(连接池)
private static ComboPooledDataSource dataSource;
static {
try {
// 使用默认配置
dataSource = new ComboPooledDataSource();
} catch (Exception e) {
e.printStackTrace();
}
}
// 获取连接
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
// 关闭连接(归还到池中)
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close(); // 实际上是归还,不是关闭
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 测试查询
public static void main(String[] args) {
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
// 获取连接
conn = getConnection();
// 执行查询
String sql = "SELECT * FROM users";
pstmt = conn.prepareStatement(sql);
rs = pstmt.executeQuery();
// 处理结果集
while (rs.next()) {
System.out.println("ID: " + rs.getInt("id") + ", Name: " + rs.getString("name"));
}
} catch (SQLException e) {
e.printStackTrace();
} finally {
// 关闭资源
closeResultSet(rs);
closePreparedStatement(pstmt);
closeConnection(conn);
}
}
// 关闭 ResultSet
public static void closeResultSet(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
// 关闭 PreparedStatement
public static void closePreparedStatement(PreparedStatement pstmt) {
if (pstmt != null) {
try {
pstmt.close();
} catch (SQLException e) {
e.printStackTrace();
}
}
}
}
Druid
添加依赖(Maven)
<dependencies>
<!-- Druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.20</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.33</version>
</dependency>
</dependencies>
配置 Druid 连接池
Druid 支持多种配置方式:代码配置、属性文件、Spring 集成。
方式一:代码方式配置
import com.alibaba.druid.pool.DruidDataSource;
import java.sql.Connection;
import java.sql.SQLException;
public class DruidExample {
private static DruidDataSource dataSource;
static {
dataSource = new DruidDataSource();
// 基本数据库配置
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC");
dataSource.setUsername("root");
dataSource.setPassword("123456");
// 连接池配置
dataSource.setInitialSize(5); // 初始连接数
dataSource.setMinIdle(5); // 最小空闲连接
dataSource.setMaxActive(20); // 最大连接数
dataSource.setMaxWait(60000); // 获取连接最大等待时间(毫秒)
dataSource.setTimeBetweenEvictionRunsMillis(60000); // 检测间隔
dataSource.setMinEvictableIdleTimeMillis(300000); // 最小空闲时间
dataSource.setValidationQuery("SELECT 1"); // 验证 SQL
dataSource.setTestWhileIdle(true); // 空闲时检测
dataSource.setTestOnBorrow(false); // 获取时检测
dataSource.setTestOnReturn(false); // 归还时检测
// 打开 PSCache(PreparedStatement 缓存)
dataSource.setPoolPreparedStatements(true);
dataSource.setMaxPoolPreparedStatementPerConnectionSize(20);
// 配置监控统计拦截器
dataSource.setFilters("stat,wall"); // stat:监控, wall:防御SQL注入
}
public static Connection getConnection() throws SQLException {
return dataSource.getConnection();
}
public static void closeConnection(Connection conn) {
if (conn != null) {
try {
conn.close(); // 归还连接
} catch (SQLException e) {
e.printStackTrace();
}
}
}
public static void main(String[] args) {
try (Connection conn = getConnection()) {
System.out.println("Druid 连接成功!");
System.out.println("连接对象: " + conn);
} catch (SQLException e) {
System.err.println("连接失败: " + e.getMessage());
}
}
}
方式二:使用 druid.properties
配置文件
在 src/main/resources/druid.properties
中配置:
# 数据库连接
druid.driverClassName=com.mysql.cj.jdbc.Driver
druid.url=jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC
druid.username=root
druid.password=123456
# 连接池配置
druid.initialSize=5
druid.minIdle=5
druid.maxActive=20
druid.maxWait=60000
druid.timeBetweenEvictionRunsMillis=60000
druid.minEvictableIdleTimeMillis=300000
druid.validationQuery=SELECT 1
druid.testWhileIdle=true
druid.testOnBorrow=false
druid.testOnReturn=false
druid.poolPreparedStatements=true
druid.maxPoolPreparedStatementPerConnectionSize=20
# 监控配置
druid.filters=stat,wall
加载配置文件的代码:
import com.alibaba.druid.pool.DruidDataSourceFactory;
import javax.sql.DataSource;
import java.io.IOException;
import java.sql.Connection;
import java.util.Properties;
public class DruidWithProperties {
private static DataSource dataSource;
static {
Properties props = new Properties();
try {
props.load(DruidWithProperties.class.getClassLoader()
.getResourceAsStream("druid.properties"));
dataSource = DruidDataSourceFactory.createDataSource(props);
} catch (Exception e) {
e.printStackTrace();
}
}
public static Connection getConnection() throws Exception {
return dataSource.getConnection();
}
public static void main(String[] args) {
try (Connection conn = getConnection()) {
System.out.println("通过配置文件连接成功!");
} catch (Exception e) {
e.printStackTrace();
}
}
}
方法三:与 Spring 集成(Spring XML 配置)
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/testdb?useSSL=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="initialSize" value="5"/>
<property name="minIdle" value="5"/>
<property name="maxActive" value="20"/>
<property name="maxWait" value="60000"/>
<property name="validationQuery" value="SELECT 1"/>
<property name="testWhileIdle" value="true"/>
<!-- 配置监控 -->
<property name="filters" value="stat,wall"/>
</bean>
启用 Druid 内置监控页面(Web 项目)
如果你使用的是 Web 项目(如 Spring Boot),可以开启 Druid 的监控页面。
1. 添加 Servlet 和 Filter(web.xml)
<!-- Druid 监控页面 -->
<servlet>
<servlet-name>DruidStatView</servlet-name>
<servlet-class>com.alibaba.druid.support.http.StatViewServlet</servlet-class>
<init-param>
<param-name>allow</param-name>
<param-value>127.0.0.1</param-value>
</init-param>
<init-param>
<param-name>deny</param-name>
<param-value></param-value>
</init-param>
<init-param>
<param-name>loginUsername</param-name>
<param-value>admin</param-value>
</init-param>
<init-param>
<param-name>loginPassword</param-name>
<param-value>123456</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>DruidStatView</servlet-name>
<url-pattern>/druid/*</url-pattern>
</servlet-mapping>
<!-- Web 监控过滤器 -->
<filter>
<filter-name>DruidWebStatFilter</filter-name>
<filter-class>com.alibaba.druid.support.http.WebStatFilter</filter-class>
<init-param>
<param-name>exclusions</param-name>
<param-value>*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>DruidWebStatFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
2. 访问监控页面
http://localhost:8080/your-app/druid
评论