ShardingSphereDataSource的Connection元数据误用,如何避免分库分表数据源问题?

摘要:背景 对于分库分表应用来说,使用org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource是一个不错的解决方案,你可以通过配置文件编写分库分表
背景 对于分库分表应用来说,使用org.apache.shardingsphere.driver.jdbc.core.datasource.ShardingSphereDataSource是一个不错的解决方案,你可以通过配置文件编写分库分表规则,从而在编码时透明地使用分表(当然,路由规则的相关字段还是要传的,之前也有文章分析过这些字段的处理过程:深入理解Mybatis分库分表执行原理)。 但是,在一些场景中是需要绕过mybatis直接做一些操作的,特别是和数据库元数据相关的操作(包括表的结构变更)。 比如我遇到的场景:先查询各个分库中有哪些前缀为table_的表,并给这些表加一列col_x。 我结合现有代码和大语言模型,先写了一版,线下运行良好,但是线上的某些分库死活找不到对应的分表,没法进行后续的处理。这个问题查了很久,昨天终于解决了,因此分享出来。 存在问题的代码 @Componet public class TableAlterHandler { @Resource private ShardingSphereDataSource dataSource; public List<String> findTablesByPrefix(String prefix, String physicalSchemaName) { if (StringUtils.isBlank(prefix) || StringUtils.isBlank(physicalSchemaName)) { throw new RuntimeException("分表前缀或分库名为空"); } List<String> tableNames = Lists.newArrayList(); try (HintManager hintManager = HintManager.getInstance(); Connection conn = dataSource.getConnection()) { hintManager.setDataSourceName(DBUtil.queryLogicalSchemaName(physicalSchemaName)); DatabaseMetaData metaData = conn.getMetaData(); try (ResultSet rs = metaData.getTables(physicalSchemaName, null, prefix + "%", new String[] {"TABLE"})) { while (rs.next()) { String tableName = rs.getString("TABLE_NAME"); tableNames.add(tableName); } } } catch (SQLException e) { throw new RuntimeException("处理大结果集失败", e); } return tableNames; } } 逻辑库和物理库 在分析问题之前,首先要明确两个概念:物理库名physicalSchemaName和逻辑库名logicalSchemaName,如果用错了,可能会让你没办法发现后续问题的本质原因。上面的代码,hintManager必须用逻辑库名,而metaData.getTables必须用物理库名。 所谓物理库和逻辑库,可以看作是我定义的概念。正如其名,物理库名就是你jdbcUrl里的库名,比如一个典型的阿里云Mysql的JDBC链接jdbc:mysql://``rm-bpxxxx.mysql.rds.aliyuncs.com/bizcenter_1?useSSL=false&autoReconnect=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai 其中的bizcenter_1就是物理库名。
阅读全文