当前位置: 首页 > news >正文

21.数据库连接池

1.不同连接池的参数配置

  • HikariCP
<!-- 配置HikariCP数据源(连接池核心Bean) -->
<bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource" destroy-method="close"><!-- 基础数据库配置 --><property name="jdbcUrl" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><!-- 连接池核心参数(和之前讲的一一对应) --><property name="maxPoolSize" value="20"/>          <!-- 最大连接数 --><property name="minIdle" value="5"/>              <!-- 最小空闲连接 --><property name="connectionTimeout" value="3000"/> <!-- 获取连接超时3秒 --><property name="idleTimeout" value="600000"/>     <!-- 空闲10分钟回收 --><property name="maxLifetime" value="1800000"/>    <!-- 连接最长存活30分钟 --><property name="testWhileIdle" value="true"/>     <!-- 空闲时验证连接有效性 -->
</bean><!-- 配置JdbcTemplate(用连接池执行SQL) -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/> <!-- 关联上面的连接池 -->
</bean>
  • Druid
<!-- 配置Druid数据源 -->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" destroy-method="close"><!-- 基础数据库配置 --><property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><!-- 连接池核心参数 --><property name="maxActive" value="20"/>          <!-- 对应Hikari的maxPoolSize --><property name="minIdle" value="5"/>             <!-- 最小空闲连接 --><property name="maxWait" value="3000"/>          <!-- 获取连接超时3秒(对应connectionTimeout) --><property name="minEvictableIdleTimeMillis" value="600000"/> <!-- 空闲超时 --><property name="maxEvictableIdleTimeMillis" value="1800000"/> <!-- 最大生命周期 --><property name="testWhileIdle" value="true"/>    <!-- 空闲时验证 --><property name="validationQuery" value="SELECT 1"/> <!-- 验证连接的SQL(MySQL) -->
</bean><!-- 配置JdbcTemplate -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/>
</bean>
  • dbcp2
<!-- 配置DBCP2数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close"><!-- 1. 基础数据库配置 --><property name="url" value="jdbc:mysql://localhost:3306/test?useSSL=false&serverTimezone=UTC"/><property name="username" value="root"/><property name="password" value="123456"/><property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/><!-- 2. 连接池核心参数(对应之前的Hikari/Druid参数) --><property name="maxTotal" value="20"/>          <!-- 最大连接数(对应Hikari的maxPoolSize) --><property name="minIdle" value="5"/>            <!-- 最小空闲连接 --><property name="maxWaitMillis" value="3000"/>   <!-- 获取连接超时时间(3秒,对应connectionTimeout) --><property name="minEvictableIdleTimeMillis" value="600000"/> <!-- 空闲连接超时回收(10分钟) --><property name="maxConnLifetimeMillis" value="1800000"/>      <!-- 连接最大生命周期(30分钟) --><!-- 3. 连接验证配置 --><property name="testWhileIdle" value="true"/>   <!-- 空闲时验证连接有效性 --><property name="validationQuery" value="SELECT 1"/> <!-- 验证连接的SQL(MySQL) --><property name="validationQueryTimeout" value="1"/> <!-- 验证超时(1秒) -->
</bean><!-- 配置JdbcTemplate(关联DBCP2连接池) -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"><property name="dataSource" ref="dataSource"/>
</bean>

2.特别重要的一个参数----最大连接数、最小空闲数

  • 传统的 DBCP 设计成动态的(minIdle < maxTotal),是为了省内存。
    没人用的时候,我只维护 5 个连接,省点 RAM。人多了,我再临时 new Connection() 涨到 20 个。

  • 现代的最佳实践变了(HikariCP 的理念):
    现在的服务器内存都很大,不差这几个连接的内存。所以 HikariCP 建议: minIdle = maxTotal
    也就是说:一上来就铺满 20 张桌子,永远不撤。
    好处: 来了客人直接坐,不需要临时去搬桌子(不需要临时建立 TCP 连接),响应最快,性能最稳。

  • 核心性能悖论:那为啥连接设很大会出现性能反而很低呢?

    操作系统(CPU 调度器)的做法: 为了公平,它不能让某个人一直占着cpu,于是它强制实行“轮班制”。
    假设cpu只有4核,但是你允许的连接数是1000,故而高并发的话,会导致1000个线程同时工作,导致cpu高频切换,cpu切换的代价也是很高的,频繁的切换导致了用于切换线程的开销(保存和恢复现场)远远高于线程正正干活的开销,故而导致性能远远下降。

    • 黄金经验公式(针对机械硬盘):\(连接数 = (CPU核心数 \times 2) + 1\)

    • 如果是 SSD 硬盘: 因为读写极快,CPU 等待时间变短,公式甚至可以接近 CPU核心数

      为什么?按照常理,设备越快,应该能处理越多的连接才对,为什么 SSD 越快,我们需要的并发连接数反而越少(越接近 CPU 核数) 呢?

      有一个经典的线程数计算公式:$$最佳线程数 = CPU核数 \times \left( 1 + \frac{等待时间 (I/O)}{计算时间 (CPU)} \right)$$

      公式里的 \(\frac{等待时间}{计算时间}\) 趋近于 0,最佳线程数 趋近于CPU核数。

    总结
    越慢的 I/O (HDD): CPU 休息时间越多 -> 需要越多备胎(连接)来填补空缺 -> 连接数要大。
    越快的 I/O (SSD/内存): CPU 休息时间越少 -> 原来的线程一个人就能把 CPU 跑满 -> 不需要备胎 -> 连接数越少(接近核数)。

3.结尾---连接池返回给我们的connetion对象
本质是代理对象,但是在dbcp连接池中,并没有使用JDK原生代理,而是重新实现了 java.sql.Connection 接口,长得和普通连接一模一样(这个实现类被称为代理类,持有connetion原始对象的引用),许多功能是直接使用原始connetion对象的,但是对于 conn.close() 此时并不是关闭物理连接(这里的close是被修改过逻辑的,不可能让你直接就去把连接给关闭了),只是将当前的connetion对象引用归还给连接池。

http://www.jsqmd.com/news/84381/

相关文章:

  • 常见API(补充)
  • 《Python实战小课:数据分析场景——解锁数据洞察之力》导读
  • 34、Python 数据持久化与序列化:从简单到关系型的全面解析
  • 放过自己,也放过你的领导
  • Part 03|当客户真的要交付时,我最先考虑的不是技术
  • 设计模式复习1
  • 我对防抖(Debounce)的一点理解与实践:从基础到立即执行
  • [网鼎杯 2020 青龙组]AreUSerialz(个人记录写题笔记,含PHP反序列化的原理、漏洞成因以及利用技巧)
  • PINN学习(三)—— 发现方程问题的解决
  • 当AI成为同事:HR的“战斗力”正在被重新定义
  • 【安卓aosp】编译报错 killed 如果处理
  • Comsol Multiphysics数值模拟
  • Windows11中使用VS2022编译运行libevent网络库
  • 不止于智能:GPT-5.1 发布,更温暖、更好聊的 ChatGPT 来啦!
  • 战网注册后显示无法登录
  • Creed —— 血液特效与敌人伤害
  • 生成式搜索优化服务商排行
  • PINBAI平板电脑维修实例
  • 大模型教我成为大模型算法工程师之day9:卷积神经网络 (CNN)
  • 优化巨型物流网络:某中心如何通过算法实现区域化转型
  • 13. django中间件
  • LangChain All In One
  • 论文解读|从“情感陪伴机器人”到“知识中介体”
  • AI大模型之Agent,RAG,LangChain(三)
  • 论文解读:多模态大模型情绪分析的承诺与现实
  • 重构 Flutter 状态管理:从 Provider 到 Riverpod 2.0 的无痛迁移与性能飞跃
  • 人工智能之数学基础:离散条件分布和连续条件概率密度
  • 精通 Flutter 网络请求:从基础 GET/POST 到拦截器 + 缓存 + 断点续传的全维度实践
  • 创客匠人峰会洞察:技术革命下知识变现的 “能力进化” 模型 —— 从 “专业者” 到 “知识超人” 的跃迁
  • 前端最新技术,零基础入门到精通,收藏这篇就够了