从Java ResultSet检查null int值


277

在Java中,我试图从ResultSet中测试是否为空值,在ResultSet中,该列将被强制转换为原始int类型。

int iVal;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
  if (rs.getObject("ID_PARENT") != null && !rs.wasNull()) {
    iVal = rs.getInt("ID_PARENT");
  }
}

从上面的代码片段中,是否有更好的方法可以做到这一点,并且我认为第二个wasNull()测试是多余的?

教育我们,谢谢


14
我发现了这个问题,因为我在数据库中有一个可为空的列,并且用Java中的Integer表示。您会认为,在数据库中具有可为空的数字列已足够普遍,以致ResultSet API可以更优雅地容纳它。
spaaarky21 2012年

我没有张贴此作为一个答案,因为它的切线和远未普及:我通常的解决办法是把IF(colName = NULL, 0, colName) AS colNameSELECT声明中(最好是在一个存储过程)。从哲学上讲,这取决于数据库是否应符合应用程序,反之亦然。由于SQL可以轻松处理NULL,而许多SQL使用者却不这样(即java.sql.ResultSet),因此我选择尽可能在DB上处理它。(当然,从概念上来说,NULL和零就等于您的目的。)
s.co.tt

Answers:


368

默认ResultSet.getInt时,字段值NULL是返回0,这也是您的默认值iVal声明。在这种情况下,您的测试是完全多余的。

如果您实际上想在字段值为NULL的情况下执行其他操作,则建议:

int iVal = 0;
ResultSet rs = magicallyAppearingStmt.executeQuery(query);
if (rs.next()) {
    iVal = rs.getInt("ID_PARENT");
    if (rs.wasNull()) {
        // handle NULL field value
    }
}

(在下面编辑为@martin注释;编写的OP代码由于iVal未初始化而无法编译)


2
我刚刚在文档中找到了相同的语句。值得在SO imho上另辟thread径。(java.sun.com/j2se/1.4.2/docs/api/java/sql/...
罗马

6
@Roman-在ResultSet中查看getInt的javadoc:“返回:列值;如果值是SQL NULL,则返回的值是0”
Cowan 2010年

150
事实的确是荒谬的。如果DB值为,getInt()则应getInteger()返回。开发人员真的搞砸了这一件事。Integernullnull
ryvantage 2014年

7
@sactiw遵循此逻辑,应该开发Java上的所有内容以避免NPE,事实并非如此。避免NPE是应用程序开发人员的责任,而不是语言内部API的责任。
Mateus Viccari '16

10
OMG为什么,根本就没有返回NULL,0NULL两个大不同的事情
deFreitas

84

另一个解决方案:

public class DaoTools {
    static public Integer getInteger(ResultSet rs, String strColName) throws SQLException {
        int nValue = rs.getInt(strColName);
        return rs.wasNull() ? null : nValue;
    }
}

27

我认为,这是多余的。rs.getObject("ID_PARENT")应该返回一个Integer对象,或者null如果列值实际上是NULL。因此,甚至应该可以执行以下操作:

if (rs.next()) {
  Integer idParent = (Integer) rs.getObject("ID_PARENT");
  if (idParent != null) {
    iVal = idParent; // works for Java 1.5+
  } else {
    // handle this case
  }      
}

5
嗯,至少在我的情况下,这样做的问题是getObject,由于我正在使用的Oracle数据库中列类型的性质,调用不一定返回Integer(“ Number”)。
Matt Mc

Matt的同样问题...使用MySQL和Types.BIGINT(应映射到a Long),该getObject()方法返回0而不是null。
xonya

2
也可以rs.getObject("ID_PARENT", Integer.class)
-Arlo

26

只需检查该字段是否正在null使用ResultSet#getObject()-1用您想要的任何空大小写值代替。

int foo = resultSet.getObject("foo") != null ? resultSet.getInt("foo") : -1;

或者,如果你能保证你使用正确的数据库列类型,以便ResultSet#getObject()真正返回Integer(因而没有LongShortByte),那么你也可以直接强制转换它的Integer

Integer foo = (Integer) resultSet.getObject("foo");

1
不,但是在非null情况下,它将构造不必要的Integer对象。(顺便说一句,大多数JDBC驱动程序在任何ResultSet方法调用期间根本不会访问db ...通常,直到所有数据通过网络传输之后,您才会获得ResultSet)。
EricS 2012年

这取决于获取大小。在大多数驱动程序中,默认值为10行,一旦检索到提取,将对它们进行处理,但是直到处理完成后才检索下一次提取。
克里斯托·阿恩

我很惊讶您的答案不是更好的答案:-)我投票赞成,因为这是避免非常棘手的不安全wasNull()方法的正确答案。对我来说,停止使用Java ;-)并继续使用VB.Net是一个补充原因,在这里RecordSet已经解决了这个简单的问题十多年了!
schlebe

11

您可以简单地使用AFAIK

iVal = rs.getInt("ID_PARENT");
if (rs.wasNull()) {
  // do somthing interesting to handle this situation
}

即使它为NULL。


5

只是Java Generics的更新。

您可以创建一个实用程序方法,以从先前强制转换的给定ResultSet中检索任何Java类型的可选值。

不幸的是,getObject(columnName,Class)不会返回null,而是给定Java类型的默认值,因此需要2次调用

public <T> T getOptionalValue(final ResultSet rs, final String columnName, final Class<T> clazz) throws SQLException {
    final T value = rs.getObject(columnName, clazz);
    return rs.wasNull() ? null : value;
}

在此示例中,您的代码如下所示:

final Integer columnValue = getOptionalValue(rs, Integer.class);
if (columnValue == null) {
    //null handling
} else {
    //use int value of columnValue with autoboxing
}

很高兴获得反馈


2

您可以使用resultSet和具有Number类型的列名称来调用此方法。它将返回Integer值,或者返回null。数据库中的空值将不返回零

private Integer getIntWithNullCheck(ResultSet rset, String columnName) {
    try {
        Integer value = rset.getInt(columnName);
        return rset.wasNull() ? null : value;
    } catch (Exception e) {
        return null;
    }
}

您能否详细介绍一下这是如何解决问题的?
英镑弓箭手

您可以使用resultSet和具有Number类型的列名称来调用此方法。它将返回Integer值,或者返回null。数据库中的空值将不会返回零。
胺kriaa

优秀的!将其编辑为答案(并在编辑后删除评论),您将获得一个不错的答案:)
Sterling Archer19年

1

使用Java 8,您可以执行以下操作:

Long nVal = Optional.ofNullable(resultSet.getBigDecimal("col_name"))
                    .map(BigDecimal::longValue).orElse(null));

在这种情况下,如果SQL值为NULL,则确保nVal将为null(而不是零)。


2
但不适用于resultSet.getInt("col_name")
猛击

1
使用MSSQL数据源,这似乎不起作用。它需要附加支票if (rs.wasNull())
alltej '18

1

为方便起见,您可以在ResultSet周围创建一个包装器类,该包装器类ResultSet通常在不返回时返回空值。

public final class ResultSetWrapper {

    private final ResultSet rs;

    public ResultSetWrapper(ResultSet rs) {
        this.rs = rs;
    }

    public ResultSet getResultSet() {
        return rs;
    }

    public Boolean getBoolean(String label) throws SQLException {
        final boolean b = rs.getBoolean(label);
        if (rs.wasNull()) {
            return null;
        }
        return b;
    }

    public Byte getByte(String label) throws SQLException {
        final byte b = rs.getByte(label);
        if (rs.wasNull()) {
            return null;
        }
        return b;
    }

    // ...

}

-6

如果可以控制SQL,另一种不错的检查方法是在查询本身中为int列添加默认值。然后只需检查该值即可。

例如,对于Oracle数据库,请使用NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

然后检查

if (rs.getInt('ID_PARENT') != -999)
{
}

当然,这也是基于以下假设:该值通常不会在该列中找到。


12
我否决了这个答案,因为它很可能给很多人带来麻烦。如果将int列定义为可为空,则它具有一组由正数,零,负数和NULL组成的值。在任何时间点,只要插入包含该幻数的有效数据行,所有突发事件都会变坏。基本上是魔数反模式的实现。不要这样
Matthias Hryniszak 2014年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.