Używam Jdbctemplate do pobierania pojedynczej wartości ciągu z bazy danych. Oto moja metoda.
public String test() {
String cert=null;
String sql = "select ID_NMB_SRZ from codb_owner.TR_LTM_SLS_RTN
where id_str_rt = '999' and ID_NMB_SRZ = '60230009999999'";
cert = (String) jdbc.queryForObject(sql, String.class);
return cert;
}
W moim scenariuszu jest całkowicie możliwe, aby NIE uzyskać trafienia w moim zapytaniu, więc moje pytanie brzmi, jak obejść następujący komunikat o błędzie.
EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
Wydawałoby mi się, że powinienem po prostu odzyskać wartość zerową zamiast rzucać wyjątek. Jak mogę to naprawić? Z góry dziękuję.
źródło
ResultSet.next()
byłby nazywany niepotrzebnie.ResultSetExtractor
W tym przypadku użycie a jest znacznie wydajniejszym narzędziem.return null
wcatch(EmptyResultDataAccessException exception){ return null; }
?Możesz także użyć
ResultSetExtractor
zamiast aRowMapper
. Oba są tak samo łatwe jak inne, jedyną różnicą jest to, że dzwoniszResultSet.next()
.ResultSetExtractor
Ma dodatkową zaletę, że można obsługiwać wszystkie przypadki, w których istnieje więcej niż jeden wiersz lub nie wierszy zwracanych.AKTUALIZACJA : Kilka lat później mam kilka sztuczek, którymi mogę się podzielić.
JdbcTemplate
działa znakomicie z lambdami java 8, dla których są przeznaczone poniższe przykłady, ale całkiem łatwo można użyć klasy statycznej, aby osiągnąć to samo.Chociaż pytanie dotyczy typów prostych, te przykłady służą jako przewodnik w typowym przypadku wyodrębniania obiektów domeny.
Po pierwsze. Załóżmy, że dla uproszczenia masz obiekt konta z dwiema właściwościami
Account(Long id, String name)
. Prawdopodobnie chciałbyś miećRowMapper
dla tego obiektu domeny.Możesz teraz używać tego mapowania bezpośrednio w metodzie do mapowania
Account
obiektów domeny z zapytania (jt
jest toJdbcTemplate
instancja).Świetnie, ale teraz chcemy uzyskać nasz pierwotny problem i używamy mojego oryginalnego rozwiązania, ponownie wykorzystując
RowMapper
do wykonania mapowania za nas.Świetnie, ale jest to wzór, który możesz i zechcesz powtórzyć. Możesz więc utworzyć ogólną metodę fabryki, aby utworzyć nową
ResultSetExtractor
dla zadania.Tworzenie
ResultSetExtractor
teraz staje się trywialne.Mam nadzieję, że pomoże to pokazać, że można teraz dość łatwo łączyć części w potężny sposób, aby uprościć domenę.
AKTUALIZACJA 2 : Połącz z opcjonalnym dla wartości opcjonalnych zamiast null.
Który teraz, gdy zostanie użyty, może mieć następujące cechy:
źródło
To nie jest dobre rozwiązanie, ponieważ w przepływie kontroli polegasz na wyjątkach. W twoim rozwiązaniu normalne jest otrzymywanie wyjątków, normalne jest umieszczanie ich w dzienniku.
źródło
ResultSet.next()
byłby wywoływany niepotrzebnie.ResultSetExtractor
W tym przypadku użycie a jest znacznie wydajniejszym narzędziem.Ok, wymyśliłem to. Po prostu zapakowałem go w próbny chwyt i odesłałem zero.
źródło
Właściwie możesz grać
JdbcTemplate
i dostosowywać własną metodę, jak chcesz. Proponuję zrobić coś takiego:Działa jak oryginał
jdbc.queryForObject
, ale bezthrow new EmptyResultDataAccessException
czasusize == 0
.źródło
UserMapper implements RowMapper<String>
.DataAccessUtils.singleResult(...)
jest tym, czego szukałem. DziękiPonieważ zwracanie wartości null, gdy nie ma danych, jest czymś, co chcę robić często podczas korzystania z queryForObject, uważam, że przydatne jest rozszerzenie JdbcTemplate i dodanie metody queryForNullableObject podobnej do poniższej.
Możesz teraz użyć tego w swoim kodzie w taki sam sposób, w jaki użyłeś queryForObject
Chciałbym wiedzieć, czy ktoś uważa, że to dobry pomysł?
źródło
Używając Java 8 lub nowszej, możesz używać
Optional
strumieni i Java.Możesz więc po prostu użyć
JdbcTemplate.queryForList()
metody, utworzyć Stream i użyć,Stream.findFirst()
który zwróci pierwszą wartość Stream lub pustyOptional
:Aby poprawić wydajność zapytania, możesz dołączyć
LIMIT 1
do zapytania, aby nie więcej niż 1 pozycja była przesyłana z bazy danych.źródło
Możesz użyć funkcji grupy, aby zapytanie zawsze zwracało wynik. to znaczy
źródło
W Postgres możesz sprawić, że prawie każde zapytanie o pojedynczej wartości zwróci wartość lub wartość null, opakowując je:
i dzięki temu unikaj złożoności rozmówcy.
źródło
Ponieważ getJdbcTemplate (). QueryForMap oczekuje minimalnego rozmiaru wynoszącego jeden, ale kiedy zwraca wartość null, pokazuje EmptyResultDataAccesso fix dis, kiedy można użyć poniższej logiki
źródło
Zajmowałem się tym już wcześniej i pisałem na wiosennych forach.
http://forum.spring.io/forum/spring-projects/data/123129-frustrated-with-emptyresultdataaccessexception
Otrzymaliśmy radę, aby użyć typu SQlQuery. Oto przykład tego, co zrobiliśmy, próbując uzyskać wartość z bazy danych, której może tam nie być.
W DAO po prostu dzwonimy ...
Nie ma jasności co do wydajności, ale działa i jest schludny.
źródło
W przypadku Byrona możesz spróbować tego ...
źródło
robić
pracy, upewnij się, że Twój jdbcTemplate jest typu
źródło
Możemy użyć zapytania zamiast queryForObject, główna różnica między zapytanie a queryForObject polega na tym, że lista zwracanych zapytań Object (oparta na typie zwracanym przez mapowanie wierszy) i ta lista może być pusta, jeśli żadne dane nie są odbierane z bazy danych, podczas gdy queryForObject zawsze oczekuje, że tylko jeden obiekt będzie pobrane z db ani null, ani wiele wierszy, aw przypadku, gdy wynik jest pusty, queryForObject rzuca EmptyResultDataAccessException, napisałem jeden kod za pomocą zapytania, które rozwiąże problem EmptyResultDataAccessException w przypadku wyniku zerowego.
źródło
Zwracanie a przez IMHO
null
jest złym rozwiązaniem, ponieważ teraz masz problem z wysłaniem i zinterpretowaniem go na (prawdopodobnie) kliencie front-end. Miałem ten sam błąd i rozwiązałem go, po prostu zwracając plikList<FooObject>
. UżyłemJDBCTemplate.query()
.Na początku (klient sieciowy Angular) po prostu sprawdzam listę i jeśli jest pusta (ma zerową długość), traktuję ją jako brak rekordów.
źródło
Po prostu łapię ten „EmptyResultDataAccessException”
wtedy możesz sprawdzić:
źródło