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连接池适配。

相关推荐
Flandern11111 小时前
HTTPS(TLS 1.3)完整流程
数据库·网络协议·计算机网络·https
Bonnie_12151 小时前
Navicat Premium连接sql server数据库
数据库
其实防守也摸鱼2 小时前
前端应用的离线暂停更新策略:构建稳定可靠的渐进式部署方案
服务器·前端·数据库·学习·ai·命令行·linux系统
Leighteen2 小时前
ORDER BY + LIMIT 的坑:为什么加了 `LIMIT` 结果顺序还乱
数据库
一个天蝎座 白勺 程序猿2 小时前
复盘之我在金仓生产环境踩过的SQL暗坑,和攒了六年的编码规矩
数据库·sql·kingbasees
Dylan的码园2 小时前
从Excel到数据库:数据分析全流程与Kettle ETL实战指南
数据库·数据分析·excel
l1t2 小时前
DeepSeek总结的DuckLake 架构深度剖析-1
数据库·架构
花生了什么事o2 小时前
分布式 ID 生成方案:从数据库自增到雪花算法
数据库·分布式·算法