Java ResultSet에서 널 int 값 확인


277

Java에서 열이 기본 int 유형 으로 캐스트되는 ResultSet에서 null 값을 테스트하려고 합니다.

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
데이터베이스에 nullable 열이 있고 Java의 Integer로 표시되기 때문에이 질문을 발견했습니다. 데이터베이스에 널 입력 가능 숫자 열을 갖는 것이 ResultSet API가 조금 더 우아하게 수용 할 수있을 정도로 일반적이라고 생각할 것입니다.
spaaarky21

이 접선 멀리 우주에서이기 때문에 나는 대답으로이 게시 아니에요 :이 내 평소 솔루션을 배치하는 것입니다 IF(colName = NULL, 0, colName) AS colNameSELECT(바람직하게는 저장된 프로 시저에) 문. 철학적으로 이것은 DB가 앱을 준수해야하는지 또는 그 반대인지에 달려 있습니다. SQL은 NULL을 쉽게 처리하고 많은 SQL 소비자는 (예를 들어 java.sql.ResultSet) 처리 하지 않기 때문에 가능한 경우 DB에서 처리하도록 선택합니다. (물론 이것은 개념적으로 NULL과 0이 목적에 상응한다고 가정합니다.)
s.co.tt

답변:


368

ResultSet.getInt필드 값 이로 설정 될 때 의 기본값 NULL은 return 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에서 별도의 스레드 가치가 있습니다. ( java.sun.com/j2se/1.4.2/docs/api/java/sql/… )
로마

6
@Roman-ResultSet에서 getInt에 대한 javadoc 참조 : "반환 : 열 값; 값이 SQL NULL 인 경우 리턴 된 값은 0"
Cowan

150
진실은 터무니없는 것입니다. getInt()해야 getInteger()반환 Integer입니다 nulldB 값 인 경우 null. 개발자들은 이것을 정말로 엉망으로 만들었습니다.
ryvantage

7
이 논리에 따라 @sactiw를 사용하면 Java의 모든 것이 NPE를 피하기 위해 개발되어야합니다. NPE는 언어 내부 API가 아닌 앱 개발자의 책임입니다.
Mateus Viccari 2016 년

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")반환해야합니다 . 따라서 다음과 같은 작업을 수행하는 것이 가능해야합니다.IntegernullNULL

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내가 사용하는 오라클 데이터베이스의 열 유형 ( "Number")의 특성으로 인해 호출 이 정수를 반환하지 않아도 된다는 것 입니다.
Matt Mc

Matt의 동일한 문제 ... MySQL에서 Types.BIGINT( 와 매핑되어야 함 Long) getObject()메소드는 null 대신 0을 반환합니다.
xonya

2
가능rs.getObject("ID_PARENT", Integer.class)
Arlo

26

필드가 null사용 중인지 확인하십시오 ResultSet#getObject(). -1원하는 널값으로 대체하십시오 .

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

또는, 그 때문에 당신이 당신이 바로 DB 컬럼 타입을 사용하는 것이 보증되는 경우에 ResultSet#getObject()정말를 반환 Integer(따라서하지 Long, ShortByte), 당신이 할 수도 그냥 배역에 Integer.

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

1
아니요, 그러나 null이 아닌 경우 불필요한 Integer 객체를 생성합니다. (그리고 BTW 대부분의 JDBC 드라이버는 ResultSet 메소드 호출 중에 db를 전혀 누르지 않습니다 ... 일반적으로 모든 데이터가 연결될 때까지 ResultSet를 다시 얻지 못합니다).
EricS

페치 크기에 따라 다릅니다. 대부분의 드라이버에서 기본값은 10 행이며 페치가 검색되면 처리되지만 처리가 완료 될 때까지 다음 페치가 검색되지 않습니다.
Kristo Aun

나는 당신의 대답이 더 나은 대답이 아니라는 것에 놀랐습니다. :-) 매우 까다로운 안전하지 않은 wasNull () 메소드를 피하는 올바른 대답이기 때문에 투표합니다. 저에게는 Java ;-) 사용을 중단하고 RecordSet이 10 년 이상이 쉬운 문제를 해결 한 VB.Net을 계속 사용하는 보충적인 이유입니다!
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 값을 리턴하거나 널을 리턴합니다. 데이터베이스에서 빈 값으로 0이 리턴되지 않습니다.

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

이것이 어떻게 문제를 해결하는지에 대해 더 자세히 설명해 주시겠습니까?
Sterling Archer

resultSet 및 Number 유형의 열 이름을 사용하여이 메소드를 호출 할 수 있습니다. Integer 값을 리턴하거나 널을 리턴합니다. 데이터베이스에서 빈 값에 대해 0이 리턴되지 않습니다.
amine kriaa

우수한! 답변으로 편집하고 편집 후 주석을 삭제하면 좋은 답변을 얻을 수 있습니다. :
Sterling Archer

1

Java 8을 사용하면 다음을 수행 할 수 있습니다.

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

이 경우 SQL 값이 NULL 인 경우 nVal이 널 (0이 아님)이되도록합니다.


2
하지만 적용되지 않습니다resultSet.getInt("col_name")
황홀한

1
MSSQL 데이터 소스에서는 작동하지 않는 것 같습니다. 추가 점검이 필요합니다if (rs.wasNull())
alltej

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 열에는 양수, 0, 음수 및 NULL로 구성된 값 세트가 있습니다. 어느 시점에서나이 마법 번호를 포함하는 유효한 데이터 행을 간단히 삽입 할 수 있으며 갑자기 모든 일이 나빠질 수 있습니다. 기본적으로 매직 넘버 안티 패턴의 구현입니다. 이러지 마
Matthias Hryniszak
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.