Ich verwende Jdbctemplate, um einen einzelnen String-Wert aus der Datenbank abzurufen. Hier ist meine Methode.
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;
}
In meinem Szenario ist es durchaus möglich, dass meine Anfrage NICHT getroffen wird. Meine Frage lautet also, wie ich die folgende Fehlermeldung umgehen kann.
EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0
Es scheint mir, dass ich einfach eine Null zurückbekommen sollte, anstatt eine Ausnahme auszulösen. Wie kann ich das beheben? Danke im Voraus.
quelle
ResultSet.next()
würden, dies ebenfalls unnötig aufgerufen würde. Die Verwendung von aResultSetExtractor
ist in diesem Fall ein viel effizienteres Werkzeug.return null
incatch(EmptyResultDataAccessException exception){ return null; }
?Sie können auch a
ResultSetExtractor
anstelle von a verwendenRowMapper
. Beide sind genauso einfach wie die anderen, der einzige Unterschied ist, dass Sie anrufenResultSet.next()
.Das
ResultSetExtractor
hat den zusätzlichen Vorteil, dass Sie alle Fälle behandeln können, in denen mehr als eine Zeile oder keine Zeilen zurückgegeben werden.UPDATE : Einige Jahre später habe ich ein paar Tricks zu teilen.
JdbcTemplate
funktioniert hervorragend mit Java 8 Lambdas, für die die folgenden Beispiele entwickelt wurden, aber Sie können ganz einfach eine statische Klasse verwenden, um dasselbe zu erreichen.Während es sich um einfache Typen handelt, dienen diese Beispiele als Leitfaden für den allgemeinen Fall des Extrahierens von Domänenobjekten.
Zuerst. Nehmen wir an, Sie haben der Einfachheit halber ein Kontoobjekt mit zwei Eigenschaften
Account(Long id, String name)
. Sie möchten wahrscheinlich einRowMapper
Objekt für diese Domain haben.Sie können diesen Mapper jetzt direkt in einer Methode verwenden, um
Account
Domänenobjekte aus einer Abfrage (jt
ist eineJdbcTemplate
Instanz) zuzuordnen .Großartig, aber jetzt wollen wir unser ursprüngliches Problem und verwenden meine ursprüngliche Lösung
RowMapper
, um das Mapping für uns durchzuführen.Großartig, aber dies ist ein Muster, das Sie möglicherweise und möglicherweise wiederholen möchten. Sie können also eine generische Factory-Methode erstellen, um eine neue
ResultSetExtractor
für die Aufgabe zu erstellen .Das Erstellen eines
ResultSetExtractor
Jetzt wird trivial.Ich hoffe, dies hilft zu zeigen, dass Sie Teile jetzt ganz einfach auf leistungsstarke Weise kombinieren können, um Ihre Domain einfacher zu gestalten.
UPDATE 2 : Kombinieren Sie mit einem optional für optionale Werte statt null.
Was jetzt, wenn es verwendet wird, Folgendes haben könnte:
quelle
Dies ist keine gute Lösung, da Sie sich auf Ausnahmen für den Kontrollfluss verlassen. In Ihrer Lösung ist es normal, Ausnahmen zu erhalten, es ist normal, sie im Protokoll zu haben.
quelle
ResultSet.next()
würden , was ebenfalls unnötig aufgerufen würde. Die Verwendung von aResultSetExtractor
ist in diesem Fall ein viel effizienteres Werkzeug.Tatsächlich können Sie mit
JdbcTemplate
Ihrer eigenen Methode spielen und diese nach Ihren Wünschen anpassen. Mein Vorschlag ist, so etwas zu machen:Es funktioniert wie das Original
jdbc.queryForObject
, aber ohnethrow new EmptyResultDataAccessException
wannsize == 0
.quelle
UserMapper implements RowMapper<String>
.DataAccessUtils.singleResult(...)
ist das, wonach ich gesucht habe. ThxDa ich bei der Verwendung von queryForObject häufig eine Null zurückgeben möchte, wenn keine Daten vorhanden sind, habe ich es als nützlich empfunden, JdbcTemplate zu erweitern und eine queryForNullableObject-Methode hinzuzufügen, die der folgenden ähnelt.
Sie können dies jetzt in Ihrem Code genauso verwenden, wie Sie queryForObject verwendet haben
Es würde mich interessieren, ob jemand anderes dies für eine gute Idee hält.
quelle
Ok, ich habe es herausgefunden. Ich habe es einfach in einen Try Catch eingewickelt und null zurückgeschickt.
quelle
Mit Java 8 oder höher können Sie einen
Optional
und Java-Streams verwenden.Sie können also einfach die
JdbcTemplate.queryForList()
Methode verwenden, einen Stream erstellen und verwenden,Stream.findFirst()
der den ersten Wert des Streams oder einen leeren Wert zurückgibtOptional
:Um die Leistung der Abfrage zu verbessern, können Sie sie
LIMIT 1
an Ihre Abfrage anhängen , sodass nicht mehr als 1 Element aus der Datenbank übertragen wird.quelle
Sie können eine Gruppenfunktion verwenden, damit Ihre Abfrage immer ein Ergebnis zurückgibt. dh
quelle
In Postgres können Sie fast jede einzelne Wertabfrage dazu bringen, einen Wert oder eine Null zurückzugeben, indem Sie sie einschließen:
und damit Komplexität im Anrufer vermeiden.
quelle
Da getJdbcTemplate (). QueryForMap eine Mindestgröße von eins erwartet, aber wenn es null zurückgibt, wird EmptyResultDataAccesso angezeigt, um zu beheben, wann die folgende Logik verwendet werden kann
quelle
Ich habe mich vorher damit befasst und in den Frühlingsforen gepostet.
http://forum.spring.io/forum/spring-projects/data/123129-frustrated-with-emptyresultdataaccessexception
Der Rat, den wir erhielten, war die Verwendung einer Art SQlQuery. Hier ist ein Beispiel dafür, was wir getan haben, als wir versucht haben, einen Wert aus einer Datenbank herauszuholen, der möglicherweise nicht vorhanden ist.
Im DAO rufen wir dann einfach an ...
Nicht klar über die Leistung, aber es funktioniert und ist ordentlich.
quelle
Für Byron können Sie dies versuchen ..
quelle
zu machen
Stellen Sie sicher, dass Ihre jdbcTemplate vom Typ ist
quelle
Wir können query anstelle von queryForObject verwenden. Der Hauptunterschied zwischen query und queryForObject besteht darin, dass die Abfragerückgabeliste des Objekts (basierend auf dem Row-Mapper-Rückgabetyp) leer ist und diese Liste leer sein kann, wenn keine Daten von der Datenbank empfangen werden, während queryForObject immer nur ein einzelnes Objekt erwartet Abgerufen von db weder null noch mehrere Zeilen und falls das Ergebnis leer ist, löst queryForObject EmptyResultDataAccessException aus. Ich hatte einen Code mit Abfrage geschrieben, der das Problem der EmptyResultDataAccessException im Falle eines Null-Ergebnisses löst.
quelle
IMHO ist die Rückgabe von a
null
eine schlechte Lösung, da Sie jetzt das Problem haben, sie auf dem (wahrscheinlichen) Front-End-Client zu senden und zu interpretieren. Ich hatte den gleichen Fehler und löste ihn, indem ich einfach a zurückgabList<FooObject>
. Ich habe benutztJDBCTemplate.query()
.Am Frontend (Angular Web Client) überprüfe ich einfach die Liste und wenn sie leer ist (Länge Null), behandle ich sie als keine Datensätze gefunden.
quelle
Ich habe gerade diese "EmptyResultDataAccessException" abgefangen.
dann können Sie überprüfen:
quelle