你是否好奇MyBatis如何高效管理数据库连接?为什么连接池能提升数倍性能?本文将深入剖析MyBatis自带连接池POOLED的实现原理,带你掌握企业级性能调优技巧!
痛点:频繁创建/关闭连接消耗70%以上时间!
优势:
类型 | 配置值 | 特点 | 适用场景 |
---|---|---|---|
无池化 | UNPOOLED | 每次操作新建连接 | 测试环境 |
自带连接池 | POOLED | 简单高效的内置池 | 中小型生产环境 |
第三方连接池 | JNDI | 使用容器(如Tomcat)提供连接 | 大型分布式系统 |
参数名 | 默认值 | 说明 | 调优建议 |
---|---|---|---|
poolMaximumActiveConnections | 10 | 最大活跃连接数 | 根据DB配置调整(50-100) |
poolMaximumIdleConnections | 5 | 最大空闲连接数 | 设为poolMaximumActive的50% |
poolMaximumCheckoutTime | 20000(ms) | 连接最大使用时间 | 避免长事务占用(建议120000) |
poolTimeToWait | 20000(ms) | 获取连接的超时等待时间 | 根据业务容忍度调整 |
poolPingQuery | null | 心跳检测SQL | 建议设置为SELECT 1 |
poolPingEnabled | false | 是否开启心跳检测 | 生产环境建议开启 |
poolPingConnectionsNotUsedFor | 0 | 连接空闲多久后执行心跳(ms) | 建议300000(5分钟) |
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mydb?useSSL=false"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="poolMaximumActiveConnections" value="50"/>
<property name="poolMaximumIdleConnections" value="25"/>
<property name="poolMaximumCheckoutTime" value="120000"/>
<property name="poolTimeToWait" value="10000"/>
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="SELECT 1"/>
<property name="poolPingConnectionsNotUsedFor" value="300000"/>
dataSource>
// 获取连接池状态
PooledDataSource pooledDS = (PooledDataSource) sqlSessionFactory
.getConfiguration().getEnvironment().getDataSource();
// 打印连接池状态
System.out.println("活跃连接: " + pooledDS.getPoolState().getActiveConnectionCount());
System.out.println("空闲连接: " + pooledDS.getPoolState().getIdleConnectionCount());
System.out.println("请求次数: " + pooledDS.getPoolState().getRequestCount());
System.out.println("等待超时次数: " + pooledDS.getPoolState().getHadToWaitCount());
场景 | 无连接池(ms) | POOLED默认(ms) | 调优后(ms) | 提升 |
---|---|---|---|---|
100次查询 | 4200 | 1200 | 850 | 395%↑ |
1000次插入 | 18600 | 5200 | 3800 | 389%↑ |
高并发(50线程) | 超时 | 23000 | 16500 | 39%↑ |
特性 | POOLED | HikariCP | Druid |
---|---|---|---|
性能 | 中等 | ⭐⭐⭐⭐⭐ 极高性能 | ⭐⭐⭐⭐ 高性能 |
监控功能 | 基础状态 | 基础监控 | ⭐⭐⭐⭐⭐ 强大监控 |
连接泄漏检测 | ❌ 不支持 | ⭐⭐ 有限支持 | ⭐⭐⭐⭐⭐ 完整支持 |
SQL防火墙 | ❌ 不支持 | ❌ 不支持 | ⭐⭐⭐⭐⭐ 支持 |
配置复杂度 | 简单 | 简单 | 复杂 |
生产环境推荐度 | 中小型应用 | 大型高并发系统 | 需要监控的场景 |
// 启用堆栈跟踪记录(需重写PooledDataSource)
public class TraceablePooledDataSource extends PooledDataSource {
private Map<Connection, Exception> connectionTraceMap = new ConcurrentHashMap<>();
@Override
public Connection getConnection() throws SQLException {
Connection conn = super.getConnection();
connectionTraceMap.put(conn, new Exception("Connection acquired at"));
return conn;
}
@Override
public void pushConnection(PooledConnection conn) throws SQLException {
connectionTraceMap.remove(conn.getRealConnection());
super.pushConnection(conn);
}
public void printLeakedConnections() {
connectionTraceMap.forEach((conn, ex) -> {
System.err.println("泄漏连接: " + conn);
ex.printStackTrace();
});
}
}
// 运行时调整连接池参数
public void adjustPoolSettings(int maxActive, int maxIdle) {
Field activeField = PooledDataSource.class.getDeclaredField("poolMaximumActiveConnections");
activeField.setAccessible(true);
activeField.set(pooledDS, maxActive);
Field idleField = PooledDataSource.class.getDeclaredField("poolMaximumIdleConnections");
idleField.setAccessible(true);
idleField.set(pooledDS, maxIdle);
System.out.println("连接池参数已更新:maxActive=" + maxActive + ", maxIdle=" + maxIdle);
}
<property name="poolPingQuery" value="
/* MySQL */ SELECT 1
/* Oracle */ SELECT 1 FROM DUAL
/* PostgreSQL */ SELECT 1
/* SQL Server */ SELECT 1
"/>
报错:Could not get a connection within 20000ms
原因:
解决:
<property name="poolMaximumActiveConnections" value="100"/>
<property name="poolTimeToWait" value="30000"/>
现象:连接数达到上限后不再释放
排查:
代码规范:
// 正确关闭资源写法
try (SqlSession session = sqlSessionFactory.openSession()) {
UserMapper mapper = session.getMapper(UserMapper.class);
// ... 业务操作
} // 自动关闭session和归还连接
报错:Communications link failure
原因:数据库主动断开空闲连接
解决方案:
<property name="poolPingEnabled" value="true"/>
<property name="poolPingQuery" value="SELECT 1"/>
<property name="poolPingConnectionsNotUsedFor" value="300000"/>
基础配置原则:
生产环境必选项:
poolPingEnabled=true
)升级建议:
黄金法则:连接池不是越大越好!过大的连接池会导致数据库性能下降,最佳连接数 = (核心数 * 2) + 有效磁盘数
最后的小测试:
当poolMaximumActiveConnections=10
且所有连接都在使用时,新的请求会?
A) 立即创建新连接
B) 等待poolTimeToWait
时间
C) 直接抛出异常
(答案:B - 在等待超时时间内尝试获取可用连接)
掌握连接池调优,让你的应用性能飞起来!