02-Oracle连接池配置实战

Oracle连接池配置实战------社保系统从20连接到200连接的血泪史

连接池不是设个数字就完了。20个连接够用的系统,接了更多下游后突然全线超时。这篇文章从社保系统的真实案例出发,拆开HikariCP连接池的配置策略------不是调参数,是找根因。

文章目录


一、从20到200------不是放大就管用

社保系统最初使用HikariCP,连接池设了20。单体应用,几个接口,20个连接绰绰有余。

后来接了省平台数据交换、银行扣款回调、养老金发放查询------一个接口进来要同时查3-4个下游。高峰期30人同时操作,每人触发一个接口,每个接口需要2-3个数据库连接------瞬间需要60-90个连接,而池子只有20个。

结果不是"第7个人被拒绝"------是所有请求都在队列里等连接。等一个连接释放,后面的请求已经超时。前端白屏。


二、HikariCP 核心参数

yaml 复制代码
spring:
  datasource:
    hikari:
      minimum-idle: 10          # 最小空闲连接,池初始化时就创建
      maximum-pool-size: 50     # 最大连接数(含空闲+使用中)
      idle-timeout: 600000      # 空闲超时(10分钟),超过则回收
      max-lifetime: 1800000     # 连接最大生存时间(30分钟),超时强制回收
      connection-timeout: 30000 # 等待连接的超时时间(30秒)
      validation-timeout: 5000  # 连接校验超时
      leak-detection-threshold: 60000 # 连接泄漏检测(60秒未归还则告警)

关键是理解三个超时的关系:

复制代码
连接生命周期:
  创建 → 借出(使用中) → 归还(空闲) → 空闲超时回收
    |                    |                |
    |              leak-detection      idle-timeout
    |                (60s告警)         (10min回收)
    |
  max-lifetime (30min强制回收)

三、连接泄漏------最隐蔽的问题

社保系统曾经出现过这样的现象:每天早上正常,下午变慢,第二天又恢复。

日志里没有报错,JVM内存正常,但 hikaricp - connection is not available, request timed out after 30000ms 间歇性出现。

leak-detection-threshold=60000 打开后,日志开始输出:

复制代码
HikariPool-1 - Connection leak detection triggered for connXX,
stack trace follows
java.lang.Exception: Apparent connection leak detected
    at com.zaxxer.hikari.HikariDataSource.getConnection
    at com.browise.service.PersonService.query(PersonService.java:156)
    ...

问题定位到 PersonService.query------某个异常分支里 try-with-resources 没有正确关闭 ResultSet,连接被吃掉了但没归还。问题发生频率每天下午高是因为下午查询量大,泄漏累积到连接池耗尽。

修法:所有数据库操作统一走 JdbcTemplate@Transactional,不在业务代码里手动管理连接。


四、连接池太大也不行------数据库侧撑不住

把连接池从20调到200后,系统确实不超时了------但Oracle数据库开始报 ORA-00020: maximum number of processes exceeded

Oracle 的 processes 参数限制了同时连接的总进程数。默认是150-300。200个HikariCP连接 + 50个其他应用连接 = 250,刚好超过。

改法不是调大连接池------是减少每个请求的连接数

java 复制代码
// 改前:一个请求打开3次连接
Connection c1 = ds.getConnection(); // 查密码
Connection c2 = ds.getConnection(); // 查状态
Connection c3 = ds.getConnection(); // 查权限

// 改后:一次连接完成所有查询
Connection c = ds.getConnection();
// 查密码、状态、权限全部在同一连接上执行

同时调整Oracle:

sql 复制代码
ALTER SYSTEM SET processes=500 SCOPE=SPFILE;
-- 重启生效

五、连接有效性校验------别每次借出都查

很多教程让配 connection-test-query: SELECT 1 FROM DUAL。HikariCP默认 需要这个------它有更高效的 isValid() 检查。

如果一定要配,不要配在借出时校验

yaml 复制代码
# 正确:只在空闲超时回收前校验
hikari:
  keepalive-time: 30000   # 每30秒心跳保活
  # 不配 connection-test-query ------ 让HikariCP用自己的isValid

只有当Oracle配置了防火墙超时断开空闲连接(如DCD/死连接检测),才需要 keepalive-time。平时不用。


六、最终配置

yaml 复制代码
spring:
  datasource:
    hikari:
      minimum-idle: 5
      maximum-pool-size: 40      # 并发×每请求连接数,加20%余量
      idle-timeout: 300000
      max-lifetime: 600000
      connection-timeout: 10000  # 10秒拿不到就报错,别让用户等
      leak-detection-threshold: 30000  # 30秒未归还告警
      keepalive-time: 60000     # 防火墙有超时断开机制时才配

核心原则:

  1. 最大连接数不是越大越好------先算并发请求×每请求连接数,再加20%
  2. 先查连接泄漏,再调连接池大小------80%的超时是泄漏导致的
  3. 减少每请求连接数比增大池子更有效------合并查询到同一个Connection
  4. leak-detection-threshold 是必开项------生产环境不开这个等于盲飞

✅ 亮点:从社保系统真实案例出发,从问题现象一路定位到根因(连接泄漏),用日志输出直接定位到出问题的代码行。扩展方向:Druid vs HikariCP对比、PolarDB/OceanBase连接池适配。

相关推荐
这个DBA有点耶6 分钟前
分布式数据库到底该不该上?从判断标准到架构选型的实战思考
数据库·架构·dba
01_ice40 分钟前
MySQL库和表的操作
数据库·mysql
布莱克6051 小时前
数据库索引分类:数据结构、物理存储与逻辑角度详解
数据结构·数据库
SelectDB1 小时前
DeepSeek Harness 接入 Litefuse:完善 Agent 可观测与评估能力
数据库
这个DBA有点耶3 小时前
从库延迟的“二次放大”效应:一次大事务,拖垮整个读写分离
数据库·mysql·架构
LearnYard3 小时前
自然语言驱动的数据图表生成:几款工具功能对比实践
数据库·百度·powerpoint
一个有温度的技术博主3 小时前
MySQL 三大日志协同机制:redo log、undo log 与 binlog 的联合运作
数据库·mysql·oracle
ltl3 小时前
ClickHouse 与 DuckDB 选型:不是同一类列存
数据库
ltl4 小时前
RocksDB WAL 与 WriteBatch:持久化与原子批写
数据库
ltl4 小时前
流批一体与增量视图:Materialize、RisingWave 与 DBSP
数据库