Mybatis连接池实现及池化模式

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

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

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

一 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;
}
相关推荐
斌味代码40 分钟前
Java SpringBoot 微服务实战:企业级架构设计与性能调优完全指南
java·spring boot·微服务
好家伙VCC41 分钟前
**发散创新:基于Go语言的服务网格实践与流量治理实战**在微服务架构日益复杂的今天,**服务网格(S
java·python·微服务·架构·golang
一定要AK9 小时前
Spring 入门核心笔记
java·笔记·spring
A__tao9 小时前
Elasticsearch Mapping 一键生成 Java 实体类(支持嵌套 + 自动过滤注释)
java·python·elasticsearch
KevinCyao9 小时前
java视频短信接口怎么调用?SpringBoot集成视频短信及回调处理Demo
java·spring boot·音视频
凯尔萨厮9 小时前
创建SpringWeb项目(Spring2.0)
spring·mvc·mybatis
迷藏4949 小时前
**发散创新:基于Rust实现的开源合规权限管理框架设计与实践**在现代软件架构中,**权限控制(RBAC)** 已成为保障
java·开发语言·python·rust·开源
wuxinyan12310 小时前
Java面试题47:一文深入了解Nginx
java·nginx·面试题
新知图书10 小时前
搭建Spring Boot开发环境
java·spring boot·后端
冰河团队10 小时前
一个拉胯的分库分表方案有多绝望?整个部门都在救火!
java·高并发·分布式数据库·分库分表·高性能