从 ResultSet Java 中获取主键列

Posted

技术标签:

【中文标题】从 ResultSet Java 中获取主键列【英文标题】:Get Primary Key Column from ResultSet Java 【发布时间】:2014-02-15 04:38:20 【问题描述】:

我正在尝试从 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 对象已经拥有我只需要获取的主键信息。

【问题讨论】:

查看ResultSetMetaDatadocs.oracle.com/javase/7/docs/api/java/sql/…的文档 【参考方案1】:

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

在我使用在结果集元数据中具有主键信息的结果集的一生中,我没有想到这一点。

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

例如,我们可能会发出类似的查询

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

在这种情况下,我们可能有也可能没有来自一个或两个表的主列,或者没有一个。

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

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

    (不是我喜欢的方式) 投射到具体实现ResultSetMetaData-class 并访问 主键信息(如果可用)。但请注意,并非每个ResultSetMetaData 实现都提供此信息。

    (更多架构方法,我这边也没有提出,但需要 如果我们处理不完整的 JDBC 驱动程序) 利用您使用的不同数据库的系统表 但当然将其隐藏在抽象中,例如桥接模式。 根据您获得的赠款,通常没什么大不了的 (包括测试基础架构部分最多 4 人天的工作和大约 1 人天的测试 您要访问的每个数据库系统) 然后,您可以从那里获得任何所需的元数据信息,包括有关外键关系的信息。

    (我的工作) 只需使用java.sql.DatabaseMetaData-class 它为每个可访问的表提供了您所需的主键信息。

这里是代码-sn-p(在 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;
    

【讨论】:

【参考方案2】:

我想使用ResultSet 检查表中的列是否是主键

mysql JDBC驱动中,如果仔细观察,java.sql.ResultSetMetaData的真正实现类应该是com.mysql.jdbc.ResultSetMetaData类。这个类提供了一个protected方法来获取每个字段的信息

protected Field getField(int columnIndex) throws SQLException 

此方法可以为您提供每个 column 索引的 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()(可能是因为它受保护) 这是因为您的类文件中已经导入了 java.sql.ResultSetMetaData。在您的类型转换中使用 com.mysql.jdbc.ResultSetMetaData 的 FQN,例如 ((com.mysql.jdbc.ResultSetMetaData) rsmd).getField(i).isPrimaryKey()。请告诉我会发生什么 是的,它的工作。你是对的,我明白了我的 IDEA IDE 之所以会因此而出人意料的原因。但是我必须检查 DB2、Oracle、Teradata API 是否存在 ResultSetMetadata 类,因为我的程序支持 7 个以上的数据库 @SID 不客气 :) 请接受答案,让其他人知道它有效。 @Keerthivasan 不,这是行不通的。当方法受到保护时,您的类应该是该方法的子类或在同一个包中。但你的方法值得赞赏。你可以使用反射来完成这项工作。 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());【参考方案3】:

使用@Keerthivasan Approach 这里是完整的工作代码。唯一的问题是答案不能使用这样的方法,因为它是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();
    



【讨论】:

这是完美的。【参考方案4】:
    // 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();
    

这适用于所有 RDBMS,而不仅仅是 MSSQL

【讨论】:

以上是关于从 ResultSet Java 中获取主键列的主要内容,如果未能解决你的问题,请参考以下文章

sql server 中 怎么让自动增1的主键列 临时的 让它可以手动插入指定值?

如何使用数据集在 C# 或 dotnet 中查找主键列名称?

如何从表中选择主键列?

以编程方式获取自动增量主键列

有哪些选项可用于获取 Snowflake 中的主键列名称?

Oracle 从主键列中选择返回空值?