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
相关推荐
hh真是个慢性子2 天前
GaussDB Inside 2.23.01.280 集中式一主一备安装
数据库·database·gaussdb·国产数据库·高斯
衍生星球3 天前
SpringBoot3 + Vue3 + 微信小程序如何学习,以及学哪些技术,组件
sql·微信小程序·uni-app·vue·springboot
她说..4 天前
Java 默认值设置方式
java·开发语言·后端·springboot
折哥的程序人生 · 物流技术专研5 天前
Java面试通关⑨:SpringBoot核心全集
自动配置·springboot·starter·校招·java面试·面试真题·内嵌容器
ShiXZ2136 天前
PDF-OCR文件识别篇(八):配置、运维与排错
java·运维·ocr·dubbo·springboot
ShiXZ2136 天前
PDF-OCR文件识别篇(七):数据入库
java·pdf·json·ocr·springboot
Gauss松鼠会8 天前
【GaussDB】GaussDB性能调优分析思路
java·前端·数据库·经验分享·算法·gaussdb
带刺的坐椅13 天前
Spring Boot → Solon 注解迁移实战指南:一张对照表说清楚
java·springboot·web·solon
十五喵源码网23 天前
基于springboot2+vue2的租房管理系统
java·毕业设计·springboot·论文笔记
whaledown23 天前
Kafka 与 Java 消息队列入门:用订单场景理解核心机制
java·kafka·消息队列·springboot