从Java ResultSet获取主键列

7

我正在尝试从ResultSet中获取表的主键列。以下是我按照以下步骤所做的:

我遵循了以下步骤:

1. SQL QUERY: Select id,subid,email,empname from Employee
2. Executed this from java.sql.Statement and got the Results in ResultSet.

这里是有趣的部分。

3. ResultSetMetadata rsmd = rs.getMetadata();

现在,如果我观察这个变量 "rsmd",它会显示相关列名的主键标志,但是我无法访问它或将其放入任何变量中。

我需要关于同样的帮助。

注意:我不想使用DatabaseMetadata及其getPrimaryKeys()函数,因为它将对外部数据库造成额外的影响。此外,ResultSetMetadata对象已经具有主键信息,我只需要获取它。


请查看 ResultSetMetaData 的文档 http://docs.oracle.com/javase/7/docs/api/java/sql/ResultSetMetaData.html - Rookie007
4个回答

10

关于您的问题以及解决方案的一些想法(希望有所帮助):

在我与具有主键信息的结果集元数据一起工作的生涯经验中,我从未想过这个问题。

这对我来说甚至很奇怪,因为原则上,结果集不限于仅显示一个表中以列组织的行,并且不强制显示一个表的所有列,甚至这些列可能不是表列。

例如,我们可能会发出像这样的查询:

select X.a, X.b, Y.n, Y.m, 'bla'||X.c||'blub'||Y.l from X, Y;

在这种情况下,我们可能有一个或者两个表中的一个或两个表都没有主键列。

正如您已经知道的那样,标准的ResultSetMetaData接口不提供主键信息的访问。在调试器中看到的是实现该接口的类的实例。

有几种方法来处理您的任务:

  1. (不是我首选的方法)
    将其强制类型转换为特定的实现ResultSetMetaData类并访问主键信息(如果可用)。但要注意,并非每个
    ResultSetMetaData实现都提供此信息。

  2. (稍微具有架构性的方法, 也不是我的建议, 但如果我们使用不完整的JDBC驱动程序,则需要)
    利用您使用的不同数据库的系统表,但当然隐藏在抽象中,例如桥接模式。 根据您拥有的授权,通常不是什么大问题 (包括基础架构部分最多需要4人天的工作以及每个要访问的数据库系统约1人天的测试)然后您可以从中获取任何所需的元数据信息,包括外键关系。

  3. (我所做的)
    只需使用Java.sql.DatabaseMetaData类 它为每个可访问表提供所需的主键信息,以及其他信息。

这里是一个Java 7的代码片段:

  public static Set<String> getPrimaryKeyColumnsForTable(Connection connection, String tableName) throws SQLException {
    try(ResultSet pkColumns= connection.getMetaData().getPrimaryKeys(null,null,tableName);) {
      SortedSet<String> pkColumnSet = new TreeSet<>();
      while(pkColumns.next()) {
        String pkColumnName = pkColumns.getString("COLUMN_NAME");
        Integer pkPosition = pkColumns.getInt("KEY_SEQ");
        out.println(""+pkColumnName+" is the "+pkPosition+". column of the primary key of the table "+tableName);
        pkColumnSet.add(pkColumnName);
      }
      return pkColumnSet;
    }

7

我有一个想法,可以使用ResultSet检查表中的列是否为主键

在MySql JDBC驱动程序中,如果您仔细查看,java.sql.ResultSetMetaData的真正实现类将是com.mysql.jdbc.ResultSetMetaData类。此类提供了一个protected方法来获取每个字段的信息。

protected Field getField(int columnIndex) throws SQLException {

这种方法可以为每个列索引提供Field实例。使用Field实例,您可以访问Field的属性。要检查它是否为主键,您可以调用:
Field.isPrimaryKey() 

使用com.mysql.jdbc.ResultSetMetaData的FQN来进行类型转换,例如:((com.mysql.jdbc.ResultSetMetaData) rsmd).getField(i).isPrimaryKey()。这是因为您不能导入两个具有相同名称的类文件并在文件中使用它们。
请阅读MySql JDBC API的Field文档以了解更多信息。希望这有所帮助!

我也尝试过,在评估 ResultSetMetadata 对象时。但这仅在评估时有效,您能详细描述如何准确获取吗?我尝试了:((ResultSetMetadata) rsmd).getField(i).isPrimaryKey() 错误:无法解析函数 getField()(可能是因为它是受保护的)。 - SID
这是因为你的类文件中已经导入了java.sql.ResultSetMetaData。在类型转换中使用com.mysql.jdbc.ResultSetMetaData的FQN,例如((com.mysql.jdbc.ResultSetMetaData) rsmd).getField(i).isPrimaryKey()。请告诉我发生了什么。 - Keerthivasan
是的,它正在工作。你说得对,我明白了为什么我的IDEA IDE表现异常。 但我需要检查DB2、Oracle、Teradata API是否存在ResultSetMetadata类,因为我的程序支持7个以上的数据库。 - SID
@SID 没有问题,不用客气 :) 请接受答案以便让其他人知道它是有效的。 - Keerthivasan
4
不行,当方法被保护时,你的类应该是其子类或者在同一个包中。但是你的方法值得赞赏。你可以使用反射来完成这项工作。method = com.mysql.jdbc.ResultSetMetaData.class.getDeclaredMethod("getField", int.class); method.setAccessible(true); com.mysql.jdbc.Field field = (com.mysql.jdbc.Field) method.invoke(resultSetMetaData, x); System.out.println(field.isPrimaryKey()); - Krishantha Dinesh
显示剩余4条评论

3

使用@Keerthivasan的方法,这里是完整的工作代码。唯一的问题是答案不能像那样使用该方法,因为它是protected方法。 下面是工作代码。

ResultSetMetaData resultSetMetaData = resultSet.getMetaData();
int count = resultSetMetaData.getColumnCount();
for (int x = 1; x <= count; x++) {

    Method method = null;
    try {
        method = com.mysql.jdbc.ResultSetMetaData.class.getDeclaredMethod("getField", int.class);
        method.setAccessible(true);
        com.mysql.jdbc.Field field = (com.mysql.jdbc.Field) method.invoke(resultSetMetaData, x);

        if (field.isPrimaryKey()) {
            System.out.println("-----------PK---------------------");
        } else {
            System.out.println("+++++++++++++++NPK++++++++++++++++++");
        }
    } catch (NoSuchMethodException e) {
        e.printStackTrace();
    } catch (IllegalAccessException e) {
        e.printStackTrace();
    } catch (InvocationTargetException e) {
        e.printStackTrace();
    }


}

1
这是完美的。 - Keerthivasan

3
    // find primary keys
    try {
        ResultSet rs = conn.getMetaData().getPrimaryKeys(null, conn.getSchema(), table);
        while (rs.next()) {
            System.out.println(rs.getString("COLUMN_NAME") + ":" + rs.getString("KEY_SEQ"));
        }
    } catch (SQLException e) {
        e.printStackTrace();
    }

这适用于所有关系型数据库管理系统,不仅限于MSSQL。

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