Sprawdzanie pustej wartości int z Java ResultSet


277

W Javie próbuję przetestować wartość pustą, z ResultSet, w którym kolumna jest rzutowana na pierwotny typ int .

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

Czy na podstawie powyższego fragmentu kodu jest lepszy sposób i zakładam, że drugi test wasNull () jest zbędny?

Edukuj nas i dziękuję


14
Znalazłem to pytanie, ponieważ mam kolumnę zerowalną w bazie danych i jest reprezentowana przez liczbę całkowitą w Javie. Można by pomyśleć, że posiadanie zerowej kolumny numerycznej w bazie danych byłoby na tyle powszechne, że interfejs API ResultSet dostosowałby ją nieco bardziej elegancko.
spaaarky21

Nie zamieszczam tego jako odpowiedzi, ponieważ jest to styczne i dalekie od uniwersalności: Moim zwykłym rozwiązaniem tego jest umieszczenie IF(colName = NULL, 0, colName) AS colNamew SELECToświadczeniu (najlepiej w przechowywanym proc). Filozoficznie sprowadza się to do tego, czy DB powinien być zgodny z aplikacją, czy odwrotnie. Ponieważ SQL obsługuje NULL z łatwością, a wielu klientów SQL nie (tj. java.sql.ResultSet), Wybieram obsługę go w DB, jeśli to możliwe. (To oczywiście zakłada, że ​​koncepcyjnie NULL i zero są równoważne dla twoich celów.)
s.co.tt

Odpowiedzi:


368

Domyślną wartością, ResultSet.getIntgdy wartość pola jest NULLzwracana 0, jest również wartością domyślną dla iValdeklaracji. W takim przypadku test jest całkowicie zbędny.

Jeśli naprawdę chcesz zrobić coś innego, jeśli wartość pola to NULL, sugeruję:

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

(Edytowane jako komentarz @martin poniżej; kod OP w formie, w jakiej został napisany, nie zostanie skompilowany, ponieważ iValnie został zainicjowany)


2
Właśnie znalazłem to samo oświadczenie w dokumentacji. Warto osobny wątek na temat SO imho. ( java.sun.com/j2se/1.4.2/docs/api/java/sql/… )
Rzym

6
@Roman - zobacz javadoc dla getInt w ResultSet: „Zwraca: wartość kolumny; jeśli wartość to SQL NULL, zwracana jest wartość 0”
Cowan

150
Prawda jest rzeczywiście absurdalna. getInt()powinno być tym, getInteger()które zwraca a Integer, to znaczy, nulljeśli wartość DB to null. Devs naprawdę to zawiedli.
ryvantage

7
@sactiw zgodnie z tą logiką, wszystko w Javie powinno zostać opracowane, aby uniknąć NPE, co nie jest prawdą. Za unikanie NPE odpowiedzialni są twórcy aplikacji, a nie wewnętrzne interfejsy API języka.
Mateus Viccari,

10
OMG Dlaczego nie, po prostu nie zwraca NULL, 0i NULLsą dwie duże różne rzeczy
deFreitas

84

Inne rozwiązanie:

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

27

Myślę, że jest zbędny. rs.getObject("ID_PARENT")powinien zwrócić Integerobiekt lub null, jeśli wartość kolumny faktycznie była NULL. Dlatego powinno być możliwe zrobienie czegoś takiego:

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
Hm, przynajmniej w moim przypadku problem polega na tym, że wywołanie getObjectniekoniecznie zwraca liczbę całkowitą, ze względu na charakter typu kolumny w bazie danych Oracle, której używam („liczba”).
Matt Mc

Ten sam problem Matta ... W MySQL i Types.BIGINT(które powinno być zamapowane na a Long) getObject()metoda zwraca 0 zamiast null.
xonya,

2
Mógłby także zrobićrs.getObject("ID_PARENT", Integer.class)
Arlo,

26

Wystarczy sprawdzić, czy pole jest używane, nullczy nie ResultSet#getObject(). Zastąp -1dowolną wartością zerową.

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

Lub, jeśli możesz zagwarantować, że użyjesz odpowiedniego typu kolumny DB, tak aby ResultSet#getObject()naprawdę zwrócił Integer(a więc nie Long, Shortlub Byte), możesz po prostu rzutować go na typ Integer.

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

1
Nie, ale zbuduje niepotrzebny obiekt Integer w przypadku różnym od null. (A BTW większość sterowników JDBC w ogóle nie dociera do bazy danych podczas żadnych wywołań metody ResultSet ... generalnie nie otrzymuje się ResultSet, dopóki wszystkie dane nie przejdą przez drut).
EricS

To zależy od wielkości pobierania. W większości sterowników wartością domyślną jest 10 wierszy i po pobraniu pobrania zostaną one przetworzone, ale następne pobieranie nie zostanie pobrane, dopóki przetwarzanie nie zostanie zakończone.
Kristo Aun

Dziwię się, że twoja odpowiedź nie jest lepszą odpowiedzią :-) Głosuję, ponieważ to właściwa odpowiedź, która pozwala uniknąć bardzo trudnej, niebezpiecznej metody wasNull (). Dla mnie jest to dodatkowy powód, aby przestać używać Java ;-) i kontynuować używanie VB.Net, w którym RecordSet rozwiązał ten łatwy problem od ponad 10 lat!
schlebe,

11

AFAIK, którego możesz po prostu użyć

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

nawet jeśli jest NULL.


5

Tylko aktualizacja z Java Generics.

Można utworzyć metodę narzędzia do pobierania opcjonalnej wartości dowolnego typu Java z danego zestawu wyników, wcześniej rzutowanego.

Niestety getObject (columnName, Class) nie zwraca null, ale domyślną wartość dla danego typu Java, więc wymagane są 2 wywołania

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;
}

W tym przykładzie Twój kod może wyglądać jak poniżej:

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

Chętnie poznamy Twoją opinię


2

Możesz wywołać tę metodę za pomocą metody wynikowej i nazwy kolumny o typie Liczba. Zwróci wartość całkowitą lub zero. W bazie danych nie będzie zwracanych zer

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

Czy możesz podać bardziej szczegółowe informacje na temat rozwiązania tego problemu?
Sterling Archer

Możesz wywołać tę metodę za pomocą metody wynikowej i nazwy kolumny o typie Liczba. Zwróci wartość całkowitą lub zero. W bazie danych nie będzie zwracanych zer.
amine kriaa

Doskonały! Edytuj to w swojej odpowiedzi (i usuń komentarz po edycji) i masz dobrą odpowiedź :)
Sterling Archer

1

W java 8 możesz to zrobić:

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

W takim przypadku upewnisz się, że wartość nVal będzie równa null (a nie zero), jeśli wartość SQL to NULL


2
ale nie dotyczyresultSet.getInt("col_name")
rapt

1
W przypadku źródła danych MSSQL to nie działa. Musi mieć dodatkową kontrolęif (rs.wasNull())
alltej

1

Dla wygody możesz utworzyć klasę opakowania wokół ResultSet, która zwraca wartości null, gdy ResultSetzwykle tego nie robi .

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

Innym dobrym sposobem sprawdzenia, czy masz kontrolę nad SQL, jest dodanie wartości domyślnej w samym zapytaniu dla kolumny int. Następnie po prostu sprawdź tę wartość.

np. w przypadku bazy danych Oracle użyj NVL

SELECT NVL(ID_PARENT, -999) FROM TABLE_NAME;

następnie sprawdź

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

Oczywiście jest to również założone, że istnieje wartość, której normalnie nie można znaleźć w kolumnie.


12
Głosowałem za odrzuceniem tej odpowiedzi, ponieważ jest bardzo prawdopodobne, że spowoduje wiele problemów. Kolumna int, jeśli jest zdefiniowana jako zerowalna, ma zestaw wartości składający się z liczb dodatnich, zera, liczb ujemnych i NULL. W dowolnym momencie można po prostu wstawić prawidłowy wiersz danych zawierający tę magiczną liczbę i nagle wszystko pójdzie źle. Jest to w zasadzie implementacja wzorca anty magicznej liczby. Nie rób tego
Matthias Hryniszak
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.