【问题标题】:jdbc ResultSet.get<DataType> returns nulljdbc ResultSet.get<DataType> 返回 null
【发布时间】:2018-12-30 20:41:59
【问题描述】:

所以我有以下问题。 我有一个通过 jdbc 连接到 Redshift-DB 的 Java 应用程序。执行一个简单的 SELECT 查询会产生一个不为空的 ResultSet(我检查过)。

现在,当我尝试从此 ResultSet 中提取数据时,该方法有时会返回 null,即使之前的 ResultSet.wasnull() 返回 false 并且在数据库中手动检查也显示有问题的记录不包含该属性的空值。

示例代码:

    private void test(){

    ResultSet rs = null;
    ResultSetMetaData rsmd = null;
    String getTable = "SELECT * from myTable"; //
    try(PreparedStatement prep = myConnection.prepareStatement(getTable
            , ResultSet.TYPE_FORWARD_ONLY
            )){
        rs = prep.executeQuery();
        rsmd = rs.getMetaData();
        int columns = rsmd.getColumnCount();

        while(rs.next()){                               // loop over all rows
            for(int col = 1; col <= columns; col++){
                if(rs.wasNull())
                    System.out.println("NULL Value detected!");

                System.out.println("Column Name: " + rsmd.getColumnName(col));
                System.out.println("Column value: " + rs.getString(col));
            }
        }

    } catch (SQLException e) {
        e.printStackTrace();
    }
}

这在大多数情况下都有效,除了某些记录之外,rs.getString(col) 只会产生空值(即使数据库中的数据类型是 CHAR 或 VARCHAR)。这不一定发生在所有列上(我已经看到有几列被正确读取和打印,直到最终出现 null,即使 wasnull() 返回 false。

到目前为止,我已经观察到 ResultSet.getString()、ResultSet.getDate() 和 ResultSet.getTimestamp() 的这种行为,但在提取任何类型的数字 (getInt()...) 时从未观察到。在所有这些情况下,我检查了数据库以确保 jdbc 方法与数据类型匹配。

我尝试使用不同的驱动程序版本,我尝试使用 rs.getBytes(col) 代替,但结果仍然相同:我只是无法摆脱那些空值。

我还成功地进行了 UNLOAD 操作,将麻烦的表卸载到 S3 并手动检查导出的 csv 文件。 UNLOAD 运行没有任何问题,CSV 对我来说看起来不错(所有值都符合预期)。

现在我当然可以通过跳过它们发生的记录来手动处理那些“不需要的 NULL”,但我宁愿避免在不了解其原因的情况下掩盖这个错误。

所以我的问题是:

我在我的代码中做一些根本错误的事情吗? jdbc / Redshift 是否存在可能导致此问题的已知问题? 有人可以向我指出一些来源或给我一些关于我可以尝试什么的想法吗?

【问题讨论】:

    标签: java jdbc amazon-redshift


    【解决方案1】:

    来自ResultSet.wasNull()的javadoc:

    报告最后读取的列是否具有 SQL NULL 的值。笔记 您必须首先在列上调用其中一个 getter 方法才能尝试 读取它的值,然后调用方法wasNull 看是否 读取的值是 SQL NULL

    返回:
    true 如果最后读取的列值是 SQL NULL,否则为 false

    换句话说,您应该阅读专栏后使用它。请注意,对于对象类型,调用 wasNull 是没有意义的,因为对象 getter 已经返回 null

    此方法旨在用于使用原始 getter(如 getInt())读取列时,因为这些将返回 0 以获得 null 值。然后,您可以使用 wasNull() 检查该值是否真的是 0 或实际上是 null

    换句话说,将您的代码更改为:

    while(rs.next()){                               // loop over all rows
        for(int col = 1; col <= columns; col++){
            String value = rs.getString(col);
            if(value == null)
                System.out.println("NULL Value detected!");
    
            System.out.println("Column Name: " + rsmd.getColumnName(col));
            System.out.println("Column value: " + value);
        }
    }
    

    或者,如果您真的想使用wasNull()(但实际上,您不应该使用!):

    while(rs.next()){                               // loop over all rows
        for(int col = 1; col <= columns; col++){
            String value = rs.getString(col);
            if(rs.wasNull())
                System.out.println("NULL Value detected!");
    
            System.out.println("Column Name: " + rsmd.getColumnName(col));
            System.out.println("Column value: " + value);
        }
    }
    

    【讨论】:

    • 谢谢,我应该更仔细地阅读 Javadoc。但是,重点仍然是我手动检查了数据库中的相关字段,并且在那里我还发现不存在 NULL,例如我会找到一个完全合理的 DATE 值,其中 rs.getDate() 只返回 null。
    • @Flo 我建议您发布一个 new 问题,该问题提供一个重现该问题的minimal reproducible example。如果这是 Redshift 驱动程序中的错误,我会感到非常惊讶。我会更早地期望使用不同的数据库或表,然后您已经检查过。
    • 我确实让应用程序通过 System.out.println() 吐出使用过的 SELECT 并使用表的完全限定名称将其粘贴到 sql Workbench 中。我还复制粘贴了 DB-url 并确保使用相同的凭据。我看不出我怎么能检查错误的数据库/表。
    • 无论如何,对于一个最小的工作示例,我还需要提供一个包含导致此行为的数据的表,并且我无法识别我可以连接的任何特征数据模式对于这些奇怪的 NULL。对我来说,这似乎完全是随机的,但是当我设置自己的测试表时,我似乎无法插入导致这些“不需要的 NULL”的数据。
    • @Flo 无论如何,我无法解决您的 Redshift 特定问题。我没有这方面的经验。我刚刚回答了错误使用 JDBC api 的原因。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-06-11
    • 2010-10-28
    • 1970-01-01
    • 2013-12-12
    • 2012-02-08
    • 2022-11-30
    • 1970-01-01
    相关资源
    最近更新 更多