Java的DatabaseMetaData.getSchemas()方法返回空的ResultSet,期望返回非空的ResultSet。

3

试图理解这里发生了什么。虽然有效的SQL查询没有问题,但是DatabaseMetaData返回一个空结果集。这不是什么大问题,因为我正在使用第二个代码示例作为解决方法。

DatabaseMetaData dmd = this.connection.getMetaData();
ResultSet rs = dmd.getSchemas();
while (rs.next()){
  // empty result set
}

预期得到的是一个非空结果集。
ResultSet rs = this.connection.prepareStatement("SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA;").executeQuery();
while (rs.next()){
  // non-empty result set with expected results
}

预期得到非空的结果集,并且已经得到了。
2个回答

3
据我所知,MySQL JDBC驱动程序认为它是一个目录,而不是一个架构。因此,你应该使用getCatalogs代替(并且在你使用它的任何地方,你需要使用目录参数而不是架构参数)。
在Connector/J中,getSchemas方法始终返回一个空结果集:

public java.sql.ResultSet getSchemas() throws SQLException {
    Field[] fields = new Field[2];
    fields[0] = new Field("", "TABLE_SCHEM", java.sql.Types.CHAR, 0);
    fields[1] = new Field("", "TABLE_CATALOG", java.sql.Types.CHAR, 0);

    ArrayList<ResultSetRow> tuples = new ArrayList<ResultSetRow>();
    java.sql.ResultSet results = buildResultSet(fields, tuples);

    return results;
}

方法 getCatalogs 返回 SHOW DATABASES 的结果。在 DatabaseMetaDataUsingInfoSchema 中,你可以看到信息模式的 TABLE_SCHEMA 列被别名为 TABLE_CAT(表示目录),并且将 catalog 参数作为查询中 TABLE_SCHEMA 列的值传递:

String sql = "SELECT TABLE_SCHEMA AS TABLE_CAT, NULL AS TABLE_SCHEM, TABLE_NAME,"
        + "COLUMN_NAME, NULL AS GRANTOR, GRANTEE, PRIVILEGE_TYPE AS PRIVILEGE, IS_GRANTABLE FROM INFORMATION_SCHEMA.COLUMN_PRIVILEGES WHERE "
        + "TABLE_SCHEMA LIKE ? AND TABLE_NAME =? AND COLUMN_NAME LIKE ? ORDER BY COLUMN_NAME, PRIVILEGE_TYPE";

java.sql.PreparedStatement pStmt = null;

try {
    pStmt = prepareMetaDataSafeStatement(sql);

    if (catalog != null) {
        pStmt.setString(1, catalog);
    } else {
        pStmt.setString(1, "%");
    }

    pStmt.setString(2, table);
    pStmt.setString(3, columnNamePattern);

有趣的是,这应该被视为一个错误吗?因为http://docs.oracle.com/javase/7/docs/api/java/sql/DatabaseMetaData.html#getSchemas()似乎暗示它应该返回一个带有模式名称的ResultSet。 - Michael Hobbs
1
@MichaelHobbs 可能不是这样,模式和目录的定义在数据库系统之间有很大的差异。MySQL所谓的模式更像是SQL标准中定义的目录。术语与MySQL内部使用的术语不匹配,这很令人困惑。 - Mark Rotteveel
1
我提交了一个错误报告,他们回复说这是一个长期存在的问题,可以追溯到早期。就像你所说的那样,这归结于模式/目录的定义方式。但仍然觉得奇怪,他们会有一个基本上什么都不做的函数。 - Michael Hobbs
1
@MichaelHobbs 我猜使用 getCatalog 的决定是在 MySQL 实现信息模式并将数据库模式称为目录之前做出的。要撤销这样的决定相当困难,因为它会破坏已经依赖它的应用程序。JDBC 规范明确指出,不存在或不支持的元数据应返回空结果集。 - Mark Rotteveel

1

我知道这是一篇旧文章,但在谷歌搜索这个主题时会出现,而且这里的答案对我没用。

经过更多挖掘,我找到了正确的方法。

首先,你可以通过以下方式获取所有元数据表类型的列表

    DatabaseMetaData metaData = connection.getMetaData();
    ResultSet rs = metaData.getTableTypes();
    while (rs.next()) {
        System.out.println(rs.getString(1));
    }

我们感兴趣的表类型简称为 TABLE
假设你的凭据有权查看它们,以下代码将提取 SQL 服务器中所有模式名称。
    DatabaseMetaData metaData = connection.getMetaData();
    ResultSet rs = metaData.getTables(null, null, null, new String[]{"TABLE"});
    while(rs.next())
    {
        System.out.println(rs.getString(1));
    }

对于我来说,使用Java 8和mysql-connector-java-8.0.22也可以正常工作。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接