蓝凌EKP产品:理解连接池、理解Hikari和Druid 区别

在日常 Java 后端开发中,我们几乎每天都在使用 Hibernate / JPA / MyBatis ,也都会配置 HikariCP、Druid 这样的连接池。

但很多人其实只停留在「会配参数」层面,对于下面这些问题并不真正清楚:

  • 什么是数据库连接池?

  • Hibernate 是在什么时候去拿数据库连接的?

  • 拿到连接之后,什么时候归还

  • 使用 HikariDataSource 和 DruidDataSource,Hibernate 的行为有没有区别?

  • Hikari 和 Druid 的差异,是不是只是"性能不一样"?

这篇文章尝试从工程视角把这些问题一次性说清楚。

一、什么是数据库连接池?

1. 为什么需要连接池?

数据库连接是一种非常昂贵的资源

  • 建立连接需要 TCP 握手、认证、会话初始化

  • 销毁连接需要数据库回收资源

  • 高并发下频繁创建 / 销毁连接,会严重拖慢系统性能

如果每次 SQL 执行都这样:

复制代码
Connection conn = DriverManager.getConnection(...);
// execute sql
conn.close();

系统在并发稍微高一点时就会崩溃。

2. 连接池的本质是什么?

一句话概括:

连接池 = 预先创建并维护一批数据库连接,统一管理、重复使用

核心思想只有两个字:

借 / 还

而不是:

创建 / 销毁

3. 一个抽象模型

复制代码
应用线程
   ↓ borrow
连接池(空闲连接 / 活跃连接)
   ↓
数据库

连接池负责:

  • 连接数量控制

  • 连接复用

  • 超时检测

  • 连接回收

  • 泄露防护

二、Hibernate 是什么时候去拿数据库连接的?

这是一个非常容易被误解的问题

❌ 常见误解

Hibernate 启动时就会占用很多数据库连接

✅ 实际情况

Hibernate 是"按需获取连接"的

1. Hibernate 不会在启动时主动占用连接

Hibernate 启动阶段主要做的是:

  • 解析实体映射

  • 初始化 SessionFactory

  • 准备缓存、拦截器等组件

不会长期持有数据库连接。


2. Hibernate 真正获取连接的时机

Hibernate 只有在以下场景,才会向 DataSource 请求连接:

场景一:真正执行 SQL

例如:

复制代码
session.save(entity);
session.createQuery("from User").list();
session.flush();

底层调用链大致是:

复制代码
Session
 → JDBC Coordinator
   → DataSource.getConnection()
场景二:事务中需要数据库交互
复制代码
@Transactional
public void doBusiness() {
    dao.save();
    dao.update();
}
  • 开启事务时 不一定立刻拿连接

  • 但在第一次真正执行 SQL 时,一定会拿

3. 一个重要结论

Hibernate 本身不"持有连接",它只是一个按需使用连接的协调者

三、Hibernate 拿到连接后,什么时候归还?

这是理解连接池行为的关键。

1. 最常见的情况(无显式事务)

复制代码
执行 SQL
 → 从连接池借连接
 → 执行完成
 → 归还连接池

一次业务方法中,可能会:

  • 多次借连接

  • 多次归还连接

2. 在 Spring 事务中的行为

复制代码
public void serviceMethod() {
    dao.save();
    dao.update();
}


xml 配置

  <property name="transactionAttributes">
            <props>
                <prop key="add*">PROPAGATION_REQUIRED</prop>
                <prop key="copy*">PROPAGATION_REQUIRED</prop>
                <prop key="update*">PROPAGATION_REQUIRED</prop>
                <prop key="save*">PROPAGATION_REQUIRED</prop>
                <prop key="delete*">PROPAGATION_REQUIRED</prop>
                <prop key="init*">PROPAGATION_REQUIRED</prop>
                <prop key="clone*">PROPAGATION_REQUIRED</prop>
                <prop key="*">PROPAGATION_REQUIRED,readOnly</prop>
            </props>
        </property>

行为是:

  1. 第一次 SQL:从连接池获取连接

  2. 事务期间:复用同一个连接

  3. 事务提交 / 回滚:

    • 调用 connection.close()

    • 实际行为是:归还连接到连接池

3. 一个非常关键的点

复制代码
connection.close();

并不等于真的关闭数据库连接

而是:

把连接"还给连接池"

真正的物理关闭,只会在:

  • 连接池缩容

  • 连接失效

  • 连接池关闭

时发生。


4. 那什么是"连接泄露"?

常见原因包括:

  • 开启事务但没有提交 / 回滚

  • 手写 JDBC 忘记关闭连接

  • 长事务 + 慢 SQL

  • 线程池任务未正确结束

这也是为什么连接池需要:

  • 超时检测

  • abandoned 回收

  • 泄露监控


四、DataSource 在 Hibernate 中扮演什么角色?

Hibernate 并不关心你用的是:

  • Hikari

  • Druid

  • C3P0

  • Tomcat Pool

它只关心一件事:

复制代码
javax.sql.DataSource

Hibernate 调用的永远是:

复制代码
DataSource.getConnection();

至于连接怎么创建、怎么复用、怎么监控,完全由连接池实现决定

设计理念

做最少的事情,跑最快的路径

特点:

  • 极简实现

  • 极短代码路径

  • 极低 GC 压力

优点:

  • 连接获取速度快

  • 吞吐量高

  • 延迟低

缺点:

  • 监控能力弱

  • SQL 可视化能力几乎没有


4. Druid:运维和诊断优先

设计理念

提供尽可能丰富的运行期观测能力

特点:

  • 内置 SQL 监控

  • Web 管理页面

  • 慢 SQL 统计

  • 泄露分析

优点:

  • 非常适合排查问题

  • 运维友好

缺点:

  • 实现复杂

  • 相比 Hikari 有一定性能开销(但通常可接受)

5. EKP提供启动后选择使用Hikari 或者Druid

修改后保存,重启可以根据可配置重新加载数据源。

复制代码
    public void afterPropertiesSet() {
        String datasourceName = ResourceUtil.getKmssConfigString("kmss.jdbc.datasource");
        DataSource datasource = defaultDataSource;
        if (StringUtil.isNotNull(datasourceName)) {
            datasource = (DataSource) context.getBean(datasourceName);
        }
        // 使用代理数据源(增加SQL监控)
        this.setTargetDataSource(new MonitoringDataSource(datasource, sqlMonitor));
        super.afterPropertiesSet();
    }

6. 对比总结

维度 HikariCP Druid
设计目标 极致性能 可观测性
吞吐量 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐
SQL 监控
运维排障 ⭐⭐ ⭐⭐⭐⭐⭐
生产稳定性 ⭐⭐⭐⭐ ⭐⭐⭐⭐

六、工程实践中的选择建议

  • 高并发、性能敏感系统:优先 Hikari

  • 复杂业务、SQL 问题多、需要排障:优先 Druid

  • 统一监控体系(JMX / APM)成熟:Hikari 完全够用

  • 中小团队、问题定位依赖连接池:Druid 更省心


七、结语

可以用这样一句话总结全文:

Hibernate 决定"什么时候用连接",连接池决定"连接怎么被管理"

理解这一点之后,你会发现:

  • 切换 Hikari 或 Druid

  • 调整连接池参数

  • 排查连接泄露问题

都会变得清晰很多。

复制代码
相关推荐
天远Date Lab5 小时前
构建金融级风控中台:Java Spring Boot 集成天远借贷风险探查 API 实战
java·大数据·spring boot·金融
Han.miracle5 小时前
数据结构与算法-012
java·开发语言
计算机毕设指导65 小时前
基于微信小程序+django连锁火锅智慧餐饮管理系统【源码文末联系】
java·后端·python·mysql·微信小程序·小程序·django
你住过的屋檐6 小时前
【oracle】oracle数据处理将一行数据根据条件拆分为多行
数据库·oracle
宋情写6 小时前
Java基础篇01-环境搭建+入门体验
java·开发语言
悟能不能悟6 小时前
java list=null,可以stream吗
java·windows·list
cike_y6 小时前
Mybatis-万能的Map&模糊查询
java·开发语言·mybatis·安全开发
开开心心_Every6 小时前
无广告干扰:简单好用文字LOGO设计工具
xml·java·网络·数据库·华为od·华为云·excel
古城小栈6 小时前
GitHub Copilot for Java:上下文感知重构建议实操
java·github·copilot