GaussDB_DWS连接池问题排查记录

GaussDB DWS 连接池报错排查记录

问题描述

项目从 MySQL 迁移到华为云 GaussDB DWS 后,每次查询必报如下错误:

复制代码
org.postgresql.util.PSQLException: ERROR: pooler: failed to send set 8 handles.

环境信息:

  • Spring Boot 3.x
  • dynamic-datasource-spring-boot3-starter
  • Druid 连接池
  • JDBC 驱动:postgresql 42.x
  • 数据库:华为云 GaussDB DWS(通过 PgBouncer 连接池代理)

排查过程

第一阶段:怀疑连接池配置问题

现象: 错误信息 pooler: failed to send set X handles,X 的数字不固定(有时是 1,有时是 8)。

初步判断: PgBouncer 连接池处于 transaction 模式,该模式不允许 JDBC 驱动在建立连接时发送 SET 初始化命令。

尝试的方案:

  • 关闭 pool-prepared-statements
  • 修改 validation-query(去掉 FROM DUAL
  • 修改 JDBC URL 参数(去掉 useSSLreWriteBatchedInserts 等)
  • 降级 Druid 版本(从 1.2.27 降到 1.2.16/1.2.21)

结果: 均无效,问题依旧。


第二阶段:确认是客户端问题还是服务端问题

关键发现:

  • Navicat 连接正常
  • 同事的另一个项目(Druid 1.2.16)连接正常
  • 本项目(Druid 1.2.27)每次必报错

结论: 服务端没问题,问题出在客户端。

进一步对比:

项目 Druid 版本 postgresql 驱动 是否正常
同事项目 1.2.16 42.3.8 ✅ 正常
本项目 1.2.27 42.7.8 ❌ 报错

第三阶段:排除连接池影响

测试1:原生 JDBC 连接

java 复制代码
String url = "jdbc:postgresql://host:port/db?currentSchema=ruoyi-vue-pro";
Connection conn = DriverManager.getConnection(url, user, password);
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT 1");
// 结果:成功

结论: 原生 JDBC 可以正常连接,说明网络和数据库本身没问题。

测试2:通过连接池执行 SELECT 1

java 复制代码
// 结果:成功

测试3:通过连接池执行 PreparedStatement

java 复制代码
PreparedStatement ps = conn.prepareStatement("SELECT COUNT(*) FROM table WHERE col = ?");
ps.setInt(1, 0);
// 结果:失败,报 failed to send set 8 handles

关键结论: SELECT 1(简单查询)成功,PreparedStatement(带参数查询)失败。问题出在 PreparedStatement 的处理上。


第四阶段:换 HikariCP 验证

将 slave 数据源从 Druid 换成 HikariCP:

yaml 复制代码
slave:
  type: com.zaxxer.hikari.HikariDataSource

结果: 同样报 failed to send set 8 handles,排除是 Druid 特有问题。


第五阶段:对比同事项目配置

仔细对比两个项目的配置,发现关键差异:

配置项 同事项目 本项目
currentSchema 写法 currentSchema=test1 currentSchema=ruoyi-vue-pro
Schema 名称 普通名称 包含连字符 -

根本原因

ruoyi-vue-pro 包含连字符 -,在 PostgreSQL/GaussDB 中,schema 名称包含特殊字符时必须用双引号包裹,否则 GaussDB 连接池在解析时会出错,触发 failed to send set handles 异常。

JDBC URL 中 currentSchema=ruoyi-vue-pro 没有加引号,导致 GaussDB 无法正确识别 schema,进而触发连接池报错。


解决方案

在 JDBC URL 中给 schema 名称加上双引号:

yaml 复制代码
# 修改前(错误)
url: jdbc:postgresql://host:port/twd?currentSchema=ruoyi-vue-pro

# 修改后(正确)
url: jdbc:postgresql://host:port/twd?currentSchema="ruoyi-vue-pro"

# 或者使用 URL 编码
url: jdbc:postgresql://host:port/twd?currentSchema=%22ruoyi-vue-pro%22

完整的推荐配置

yaml 复制代码
spring:
  autoconfigure:
    exclude:
      - com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  datasource:
    dynamic:
      primary: master
      datasource:
        master:
          driver-class-name: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://host:port/db?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true&rewriteBatchedStatements=true
          username: xxx
          password: xxx
        slave:
          driver-class-name: org.postgresql.Driver
          url: jdbc:postgresql://host:port/twd?currentSchema="ruoyi-vue-pro"
          username: xxx
          password: xxx
          druid:
            validation-query: SELECT 1
            test-while-idle: true
            test-on-borrow: true
            test-on-return: false
            pool-prepared-statements: false

经验总结

  1. Schema 名称包含特殊字符(如连字符 -、空格等)时,必须用双引号包裹,否则在 GaussDB/OpenGauss 的连接池代理层会解析失败。

  2. 排查此类问题的有效方法:

    • 先用原生 JDBC DriverManager.getConnection 验证连接是否正常
    • 再用简单 SELECT 1PreparedStatement 分别测试,定位问题层级
    • 对比能用的项目和不能用的项目的配置差异,重点看 URL 参数
  3. 使用 dynamic-datasource 多数据源时,必须排除 DruidDataSourceAutoConfigure,否则会导致数据源初始化冲突。

  4. GaussDB DWS 连接注意事项:

    • Schema 名称含特殊字符必须加双引号
    • 不要使用 useSSL=true(连接池代理通常不支持)
    • 不要开启 pool-prepared-statements
    • validation-query 使用 SELECT 1,不要加 FROM DUAL

相关错误对照表

错误信息 可能原因
pooler: failed to send set X handles Schema 名称含特殊字符未加引号;或 PgBouncer 为 transaction 模式
Read timed out 连接空闲超时被服务端断开;或 socketTimeout 设置过小
oid type true not known Druid 版本与 postgresql 驱动版本不兼容
keepAliveBetweenTimeMillis must be greater than timeBetweenEvictionRunsMillis keepAlive 时间需大于 timeBetweenEvictionRunsMillis
相关推荐
小博测试成长之路15 小时前
55分钟能用飞算JavaAI搭完JWT REST API吗?
springboot·ai编程·java开发·飞算javaai·ai coding·java代码生成
努力就够了15 小时前
搭建属于自己的 AI 智能体以及多 Agent 协作
springboot·ai agent·ai 智能体·多 agent 协作
chaser&upper18 小时前
飞算JavaAI能听懂食品安全召回系统的复杂业务吗?
springboot·crud·vibe coding·飞算javaai·ai coding模型
承渊政道1 天前
10:30提交预约会不会撞上10:00的会议?我用飞算JavaAI3.9.1和3.9.9跑了四个时间段
java·springboot·ai编程·飞算javaai·java代码生成
坐吃山猪2 天前
WebClient内存配置解析
开发语言·springboot·webflux
Pocker_Spades_A2 天前
飞算JavaAI 48分钟能做完Java全栈项目吗?
java·springboot·#ai编程·#飞算javaai·#java代码生成·#aicoding模型·#java开发
孔明click332 天前
Sa-Token v1.46.0 发布 🚀,来看看有没有令你心动的功能!
java·sa-token·开源·springboot·权限认证
云边有个稻草人3 天前
飞算JavaAI能处理SaaS套餐变更业务吗?
java·springboot·ai编程·java开发·飞算javaai·java代码生成·ai coding模型
todoitbo3 天前
飞算JavaAI的多租户权限隔离实测
java·springboot·ai编程·java开发·飞算javaai·java代码生成
闲猫3 天前
Docker本地用Dockfile 构建Java后端SprintBoot镜像
docker·springboot·dockerfile