Mybatis连接池实现及池化模式

MyBatis 使用 javax.sql.DataSource 标准接口,通过工厂模式创建不同类型的数据源实现。使用对象池模式实现PooledDataSource,用代理模式改变Connection#close方法逻辑,实现资源归还。

理解MyBatis中连接池的实现,可为学习其他组件如Druid 、HikariCP打好基础。

注:本文中源码来自mybatis 3.4.x版本,地址https://github.com/mybatis/mybatis-3.git

一 DataSourceFactory接口

工厂模式,声明创建DataSource实例方法,有3个实现:

  • UnpooledDataSourceFactory,用于创建UnpooledDataSource
  • PooledDataSourceFactory,继承自UnpooledDataSourceFactory,用于创建PooledDataSource
  • JndiDataSourceFactory,第三方 DataSource (通过 JNDI 获取)

二 3种连接池

2.1 UnpooledDataSource

非池化数据源,有以下特点:

  • 每次 getConnection() 都创建新的数据库连接
  • 通过 DriverManager 获取连接
  • 适用于简单应用或测试环境

核心属性如下。每次获取连接,都直接调用DriverManager.getConnection创建一个实例。

2.2 PooledDataSource

池化数据源,维护一个池子(其实就是List),复用数据库连接,基于 UnpooledDataSource 实现。

PooledDataSource内部持有 UnpooledDataSource 创建真实连接,维护 PoolState 管理连接状态,使用动态代理拦截Connection.close() 方法,将连接归还到池子而非真的关闭。

连接池配置如下

连接池状态主要参数如下,使用中连接、空闲连接分别放在不同的List。

从PooledDataSource中获取到的连接,其实是一个代理对象。

PooledConnection

PooledDataSource池中其实是PooledConnection对象(并没有实现Connection接口),它持有Connection实例、Connection代理对象,并且实现了InvocationHandler接口,声明了动态代理逻辑:

  • 代理连接调用close方法时,会将连接放回连接池;
  • 代理连接调用其他非Object的方法时,会先检查连接是否有效;
  • 记录连接创建时间、最后一次使用时间、借出时间,用于连接有效性管理;

获取/归还连接

2.3 JndiDataSourceFactory

从 JNDI 上下文获取已配置的 DataSource,适用于应用服务器环境(如 Tomcat、WebLogic),不直接创建连接,而是使用容器管理的数据源。

三 池化模式实现

3.1 Mybatis的启发

MyBatis 的 PooledDataSource 虽然简单,但包含了池化技术的核心思想,比如:

  • 对象复用而非对象共享

池化不是简单地复用对象本身,而是复用昂贵的底层资源(真实连接),通过新包装对象隔离使用状态。

java 复制代码
// 关键启发:归还时创建新的包装对象
PooledConnection newConn = new PooledConnection(conn.getRealConnection(), this);
state.idleConnections.add(newConn);
conn.invalidate(); // 旧对象失效
  • 动态代理拦截资源释放

通过代理模式透明地改变资源释放行为,用户无感知地实现池化。

java 复制代码
// PooledConnection 实现 InvocationHandler
public Object invoke(Object proxy, Method method, Object[] args) {
    if (CLOSE.equals(methodName)) {
        // 归还而非关闭
        dataSource.pushConnection(this);
        return null;
    }
    return method.invoke(realConnection, args);
}
  • 超时强制回收机制

防止资源泄漏的最后防线,避免因使用方忘记释放导致池耗尽。

java 复制代码
if (longestCheckoutTime > poolMaximumCheckoutTime) {
    // 强制回收超时连接
    state.activeConnections.remove(oldestActiveConnection);
    conn = new PooledConnection(oldestActiveConnection.getRealConnection(), this);
}
  • 状态与健康管理

除了检查资源状态,还需检查池中的connection是否断连。

java 复制代码
protected boolean pingConnection(PooledConnection conn) {
    // 1. 检查连接是否关闭
    // 2. 可选:执行 ping 查询测试
    // 3. 长时间未使用才 ping,避免频繁测试
}
  • 监控与可观测性

设计详细的统计信息,便于分析性能、调优和问题诊断。

java 复制代码
protected long requestCount;                    // 请求总数
protected long accumulatedRequestTime;          // 累计请求时间
protected long accumulatedCheckoutTime;         // 累计借出时间
protected long badConnectionCount;              // 坏连接数
protected long hadToWaitCount;                  // 等待次数

3.2 通用池化实现

基于以上分析,可以抽象出通用的池化实现模式:

java 复制代码
public class GenericObjectPool<T> {
    // 1. 双列表管理
    private List<PooledObject<T>> idle = new ArrayList<>();
    private List<PooledObject<T>> active = new ArrayList<>();
    
    // 2. 配置参数
    private int maxTotal;
    private int maxIdle;
    private long maxWaitMillis;
    
    // 3. 获取资源
    public T borrow() {
        synchronized (lock) {
            // 优先从空闲列表获取
            // 其次创建新对象
            // 或回收超时对象
            // 最后等待
            lock.wait(maxWaitMillis);
        }
    }
    
    // 4. 归还资源
    public void return(T obj) {
        synchronized (lock) {
            // 验证有效性
            // 重置状态
            // 放回空闲列表或销毁
            lock.notifyAll();
        }
    }
    
    // 5. 健康检查
    private boolean validate(T obj) {
    }
    
    // 6. 统计监控
    private PoolStats stats;
}
相关推荐
神奇小汤圆4 小时前
学完 Spring Boot 再看 FastAPI,我破防了
后端
Vergelight4 小时前
实战拆解|三类RAG架构差异:朴素、进阶、多轮RAG落地选型指南
架构·大模型·aigc·agent·ai产品经理·转行·ai后台设计
开发小能手-roy4 小时前
Java集合框架选型指南:从ArrayList到ConcurrentSkipListMap
java·开发语言
凡人叶枫4 小时前
Effective C++ 条款41:了解隐式接口和编译期多态
java·开发语言·c++·effective c++
凡人叶枫4 小时前
Effective C++ 条款42:了解 typename 的双重意义
java·linux·服务器·c++
chushiyunen5 小时前
java中的路径处理、左右斜杠
java·开发语言·python
用户987409238875 小时前
deepspeed zero3 + llamafactory 保存checkpoint后第一step 就 OOM
后端
长大19885 小时前
ggplot2 高阶美化:SCI 期刊级论文图表从零绘制全流程
后端
Database_Cool_5 小时前
大规模数据分析降本指南:AnalyticDB Serverless 弹性架构实战
数据仓库·阿里云·架构·数据分析·serverless
yyxx4121235 小时前
上海企业如何选择专业的钉钉服务商
java·大数据·人工智能·钉钉