ShardingSphere 启动报错 “Unknown table ‘keywords‘ in information_schema“ 完整解决方案

问题背景

在使用 Spring Boot 2.6.8 + ShardingSphere 4.1.1 的项目中,启动应用时遇到如下错误:

java.sql.SQLSyntaxErrorException: Unknown table 'keywords' in information_schema
    at com.mysql.cj.jdbc.DatabaseMetaDataUsingInfoSchema.getSQLKeywords(DatabaseMetaDataUsingInfoSchema.java:1193)

完整的错误堆栈显示,这个错误发生在 Spring Boot Actuator 的健康检查阶段,导致整个应用无法启动。

技术栈环境

  • Spring Boot: 2.6.8
  • ShardingSphere: 4.1.1
  • MySQL: 8.0.x (低于 8.0.13)
  • MySQL Connector: mysql-connector-java
  • 数据源: Dynamic DataSource + ShardingSphere

问题原因深度分析

为什么会报这个错?

这个问题的发生链路如下:

Spring Boot 启动
    ↓
Spring Boot Actuator 健康检查
    ↓
检查 shardingDataSource 健康状态
    ↓
ShardingSphere 初始化数据源
    ↓
MySQL JDBC 驱动查询元数据
    ↓
调用 DatabaseMetaDataUsingInfoSchema.getSQLKeywords()
    ↓
执行 SQL: SELECT * FROM information_schema.KEYWORDS
    ↓
报错:表不存在 ❌

核心矛盾

information_schema.KEYWORDS 表只在 MySQL 8.0.13+ 版本中存在!

  • 如果你的 MySQL 版本 < 8.0.13,这个表根本不存在
  • MySQL JDBC 驱动(特别是新版本)会默认使用 information_schema 来查询元数据
  • ShardingSphere 在初始化时会触发驱动的元数据查询

三个”罪魁祸首”

  1. Spring Boot Actuator – 启动时主动检查数据库健康状态
  2. ShardingSphere – 启动时会进行表元数据检查
  3. MySQL JDBC 驱动 – 默认使用 information_schema 查询关键字列表

解决方案(三管齐下)

我们需要从三个层面同时解决问题,确保万无一失。

方案一:禁用 Spring Boot Actuator 的数据库健康检查

为什么这样做?
从源头上阻止健康检查触发数据源初始化,避免问题发生。

配置方法:

在 application.yml 或 application-{profile}.yml 中添加:

management:
  health:
    db:
      enabled: false

优点:

  • 立竿见影,直接阻止健康检查
  • 不影响应用正常使用数据库

缺点:

  • 失去了数据库健康检查的功能(可用其他监控方案补充)

方案二:禁用 ShardingSphere 的表元数据检查

为什么这样做?
即使数据源被初始化,也跳过不必要的元数据校验。

配置方法:

在 ShardingSphere 配置中添加 props 节点:

spring:
  sharding-sphere:
    datasource:
      names: hotel-resource-supplier
      hotel-resource-supplier:
        type: com.zaxxer.hikari.HikariDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://your-host:3306/your_db?serverTimezone=Asia/Shanghai
        username: your_username
        password: your_password
    sharding:
      tables:
        your_table:
          actual-data-nodes: ds.your_table$->{0..7}
          table-strategy:
            inline:
              sharding-column: id
              algorithm-expression: your_table$->{id % 8}
    # 关键配置:禁用表元数据检查
    props:
      sql.show: false
      check-table-metadata-enabled: false

配置说明:

  • check-table-metadata-enabled: false – 禁用启动时的表结构校验
  • sql.show: false – 关闭 SQL 日志(可选,根据需要调整为 true)

优点:

  • 不影响 ShardingSphere 的分片功能
  • 只是跳过启动时的元数据校验步骤

方案三:JDBC URL 添加参数禁用 information_schema

为什么这样做?
告诉 MySQL JDBC 驱动不要使用 information_schema,改用 SHOW 命令查询元数据。

配置方法:

在 JDBC URL 中添加 useInformationSchema=false 参数:

spring:
  sharding-sphere:
    datasource:
      hotel-resource-supplier:
        jdbcUrl: jdbc:mysql://your-host:3306/your_db?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&useInformationSchema=false

完整示例:

spring:
  sharding-sphere:
    datasource:
      names: hotel-resource-supplier
      hotel-resource-supplier:
        type: com.zaxxer.hikari.HikariDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        jdbcUrl: jdbc:mysql://jump-hw.xxx.com:33061/hotel_resource_supplier?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true&useInformationSchema=false
        username: ${DB_USER:your_username}
        password: ${DB_PWD:your_password}

优点:

  • 即使需要查询元数据,也使用兼容性更好的 SHOW 命令
  • 适用于所有 MySQL 版本

完整配置示例

application-uat.yml 完整配置

spring:
  autoconfigure:
    exclude: com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceAutoConfigure
  datasource:
    dynamic:
      primary: ceekee_hotel_resource
      datasource:
        ceekee_hotel_resource:
          type: com.zaxxer.hikari.HikariDataSource
          driverClassName: com.mysql.cj.jdbc.Driver
          url: jdbc:mysql://your-host:3306/ceekee_hotel_resource?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false
          username: your_username
          password: your_password

  sharding-sphere:
    datasource:
      names: hotel-resource-supplier
      hotel-resource-supplier:
        type: com.zaxxer.hikari.HikariDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        # 方案三:添加 useInformationSchema=false
        jdbcUrl: jdbc:mysql://your-host:3306/hotel_resource_supplier?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=false&rewriteBatchedStatements=true&useInformationSchema=false
        username: your_username
        password: your_password
    sharding:
      tables:
        international_supplier_hotel_room_type:
          actual-data-nodes: hotel-resource-supplier.international_supplier_hotel_room_type$->{0..7}
          table-strategy:
            inline:
              sharding-column: hotel_id
              algorithm-expression: international_supplier_hotel_room_type$->{hotel_id % 8}
        international_supplier_hotel_room_type_image:
          actual-data-nodes: hotel-resource-supplier.international_supplier_hotel_room_type_image$->{0..7}
          table-strategy:
            inline:
              sharding-column: hotel_id
              algorithm-expression: international_supplier_hotel_room_type_image$->{hotel_id % 8}
    # 方案二:禁用元数据检查
    props:
      sql.show: false
      check-table-metadata-enabled: false

# 方案一:禁用健康检查
management:
  health:
    db:
      enabled: false

方案对比与选择建议

方案生效层级推荐指数适用场景
方案一:禁用健康检查Spring Boot⭐⭐⭐⭐⭐不需要数据库健康检查功能的项目
方案二:禁用 ShardingSphere 元数据检查ShardingSphere⭐⭐⭐⭐使用 ShardingSphere 的项目
方案三:JDBC 参数MySQL JDBC 驱动⭐⭐⭐⭐⭐所有使用 MySQL 的项目

推荐组合

最佳实践:三个方案同时使用

虽然理论上只需要其中一个方案即可解决问题,但为了确保在各种情况下都不会出错,建议三个方案同时配置:

  1. 方案一 在最外层拦截,避免触发问题
  2. 方案二 在 ShardingSphere 层拦截,即使触发也跳过
  3. 方案三 在 JDBC 层拦截,即使要查询也用兼容方式

这样形成三层防护,确保万无一失。


验证方案是否生效

配置完成后,重新启动应用,观察日志:

成功的日志标志

INFO  o.s.boot.web.embedded.tomcat.TomcatWebServer - Tomcat started on port(s): 16531 (http)
INFO  c.c.h.a.front.TripwiseHotelAbroadFrontApplication - Started TripwiseHotelAbroadFrontApplication in 12.345 seconds

不应该再出现的错误

❌ java.sql.SQLSyntaxErrorException: Unknown table 'keywords' in information_schema
❌ Error creating bean with name 'shardingDataSource'
❌ Error creating bean with name 'healthEndpoint'

常见问题 FAQ

Q1: 禁用健康检查会影响生产监控吗?

A: 不会。你可以通过以下方式补充监控:

  • 使用独立的数据库监控工具(如 Prometheus + Grafana)
  • 在业务代码中自定义健康检查逻辑
  • 使用数据库自带的监控功能

Q2: 为什么不直接升级 MySQL 到 8.0.13+?

A: 升级数据库涉及以下风险:

  • 需要停机维护
  • 可能存在兼容性问题
  • 需要充分的测试
  • 不是所有环境都能随意升级

使用配置解决是最低风险的方案。

Q3: 这个配置会影响 ShardingSphere 的分片功能吗?

A: 完全不会。这些配置只是:

  • 跳过启动时的健康检查
  • 跳过元数据校验
  • 改变元数据查询方式

分片规则、路由策略、SQL 解析等核心功能完全不受影响。

Q4: 如果只配置其中一个方案可以吗?

A: 可以,但不推荐。建议三个方案都配置,原因:

  • 配置成本极低(只需要几行配置)
  • 三层防护更可靠
  • 避免因环境差异导致的问题

扩展:其他类似问题

如果你遇到以下类似错误,也可以使用相同的解决方案:

Unknown table 'CHECK_CONSTRAINTS' in information_schema
Unknown table 'TABLESPACES' in information_schema
Unknown table 'ST_GEOMETRY_COLUMNS' in information_schema

这些都是因为 MySQL 版本差异导致的 information_schema 表不存在问题,使用 useInformationSchema=false 即可解决。


总结

问题本质

MySQL 8.0.13 版本引入了新的系统表 information_schema.KEYWORDS,但老版本 MySQL 没有这个表。当新版本的 MySQL JDBC 驱动尝试查询这个表时,就会报错导致应用无法启动。

解决思路

从三个层面同时阻断问题发生的路径:

  1. 应用层:禁用不必要的健康检查
  2. 中间件层:跳过 ShardingSphere 的元数据校验
  3. 驱动层:让 JDBC 使用兼容性更好的查询方式

核心价值

  • ✅ 快速解决:无需升级 MySQL,几分钟配置即可解决
  • ✅ 零风险:不影响任何业务功能
  • ✅ 通用性强:适用于所有 ShardingSphere + MySQL 项目
  • ✅ 防患未然:三层防护确保不会复发

最后的建议

虽然这个问题看起来很棘手,但本质上是版本兼容性问题。在无法立即升级数据库的情况下,通过合理的配置可以完美解决。

记住:最好的解决方案不是最复杂的,而是最稳定、最容易理解和维护的。


参考资料


作者: Claude Code
创建时间: 2025-12-16
适用版本: Spring Boot 2.x + ShardingSphere 4.x + MySQL 5.7/8.0
关键词: ShardingSphere, MySQL, information_schema, KEYWORDS, 启动报错

作者: oliver

全栈开发者与创业合伙人,拥有十余年技术实战经验。​AI编程践行者,擅长以产品思维打造解决实际问题的工具,如书签系统、Markdown转换工具及在线课表系统。信仰技术以人为本,专注氛围编程与高效协作。

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注