DatabaseMetaData#getTables无返回值——通用JDBC程序表查询异常
解决DatabaseMetaData#getTables无法获取表数据的问题
我来帮你梳理下这个问题——你在开发通用数据库工具时遇到的getTables()返回空结果的情况,在跨数据库适配场景里其实挺常见的,尤其是MySQL这类对catalog和schema有特殊映射逻辑的数据库。
问题根源
从你的输出能看到,MySQL/MariaDB的getCatalogs()返回的是你的各个数据库实例(比如seyehat、test),而MySQL的JDBC驱动里,catalog对应数据库名,schema则可以忽略(设为null)。你调用getTables(null, null, "%", null)时,传入的null catalog让驱动不知道该查询哪个数据库,自然返回空结果。
另外,不同数据库对catalog和schema的定义差异很大:
- MySQL/MariaDB:catalog = 数据库名,schema无实际意义(可设为null)
- Oracle:catalog = null,schema = 用户名(比如SYSTEM、SCOTT)
- Derby:嵌入式模式下,catalog = 数据库名,默认schema为
APP
分步解决方案
1. 先做临时验证(针对MySQL)
你可以先指定具体的catalog(比如你的业务库seyehat)来测试,同时明确指定表类型为TABLE(避免返回视图、系统表等无关数据):
// 查询seyehat库下的所有普通表 ResultSet rsTables = dm.getTables("seyehat", null, "%", new String[]{"TABLE"}); while (rsTables.next()) { // 第三个字段是表名 System.out.println(rsTables.getString(3)); } rsTables.close();
同样,getColumns()也要对应修改参数,指定正确的catalog:
ResultSet columns = dm.getColumns("seyehat", null, "kontrol", null); // 后续遍历逻辑不变
执行这段代码应该就能拿到你要的表和字段数据了。
2. 跨数据库通用适配方案
要同时支持MySQL、Oracle、Derby,需要根据数据库类型动态处理catalog和schema参数:
try { DatabaseMetaData dm = connection.getMetaData(); String productName = dm.getDatabaseProductName(); ResultSet rsTables; // 数据库基础信息输出(保留你的原有逻辑) System.out.println("Database Info\n---------------------------------\n"); System.out.println(dm.getDatabaseProductName()); System.out.println(dm.getDriverName()); System.out.println(dm.getDriverVersion()); System.out.println(dm.getDatabaseProductVersion()); // 处理不同数据库的表查询逻辑 System.out.println("Tables\n---------------------------------\n"); if (productName.contains("MySQL") || productName.contains("MariaDB")) { // 遍历所有业务catalog(跳过系统库) ResultSet rsCatalogs = dm.getCatalogs(); while (rsCatalogs.next()) { String catalog = rsCatalogs.getString(1); // 跳过MySQL系统库 if (!catalog.equals("information_schema") && !catalog.equals("mysql") && !catalog.equals("performance_schema") && !catalog.equals("phpmyadmin")) { System.out.println("> Catalog: " + catalog); rsTables = dm.getTables(catalog, null, "%", new String[]{"TABLE"}); while (rsTables.next()) { System.out.println(" - " + rsTables.getString(3)); } rsTables.close(); } } rsCatalogs.close(); } else if (productName.contains("Oracle")) { // Oracle用schema(用户名)查询 ResultSet rsSchemas = dm.getSchemas(); while (rsSchemas.next()) { String schema = rsSchemas.getString(1); System.out.println("> Schema: " + schema); rsTables = dm.getTables(null, schema, "%", new String[]{"TABLE"}); while (rsTables.next()) { System.out.println(" - " + rsTables.getString(3)); } rsTables.close(); } rsSchemas.close(); } else if (productName.contains("Derby")) { // Derby默认schema为APP,可根据实际情况调整 System.out.println("> Schema: APP"); rsTables = dm.getTables(null, "APP", "%", new String[]{"TABLE"}); while (rsTables.next()) { System.out.println(" - " + rsTables.getString(3)); } rsTables.close(); } // 字段查询也需要对应调整(以MySQL为例,其他数据库同理) System.out.println("\nColumns of kontrol\n---------------------------------\n"); if (productName.contains("MySQL") || productName.contains("MariaDB")) { ResultSet columns = dm.getColumns("seyehat", null, "kontrol", null); while (columns.next()) { String columnName = columns.getString("COLUMN_NAME"); String datatype = columns.getString("DATA_TYPE"); String columnsize = columns.getString("COLUMN_SIZE"); String decimaldigits = columns.getString("DECIMAL_DIGITS"); String isNullable = columns.getString("IS_NULLABLE"); String is_autoIncrment = columns.getString("IS_AUTOINCREMENT"); System.out.println(columnName + "---" + datatype + "---" + columnsize + "---" + decimaldigits + "---" + isNullable + "---" + is_autoIncrment); } columns.close(); } } catch (SQLException e) { e.printStackTrace(); }
额外注意事项
- 驱动版本:你当前使用的
mysql-connector-java-5.1.45连接MariaDB 10.1.x虽然可行,但升级到8.x版本的驱动(比如mysql-connector-java-8.0.33)会对catalog/schema的处理更规范,也能支持新版数据库特性。 - 权限问题:确保你的数据库账号拥有足够的权限,比如MySQL用户需要有
SELECT权限在目标数据库上,否则即使参数正确也会返回空结果。
内容的提问来源于stack exchange,提问作者hkn
相关产品推荐
相关产品推荐

