JdbcTemplate queryForInt / Long ist in Spring 3.2.2 veraltet. Womit soll es ersetzt werden?

103

Die queryforInt / queryforLong-Methoden in JdbcTemplate sind in Spring 3.2 veraltet. Ich kann nicht herausfinden, warum oder was als die beste Vorgehensweise angesehen wird, um vorhandenen Code mit diesen Methoden zu ersetzen.

Eine typische Methode:

int rowCount = jscoreJdbcTemplate.queryForInt(
    "SELECT count(*) FROM _player WHERE nameKey = ? AND teamClub = ?",
    playerNameKey.toUpperCase(),
    teamNameKey.toUpperCase()
);

OK, die obige Methode muss wie folgt neu geschrieben werden:

Object[] params = new Object[] { 
   playerNameKey.toUpperCase(), 
   teamNameKey.toUpperCase()
};
int rowCount = jscoreJdbcTemplate.queryForObject(
    "SELECT count(*) FROM _player WHERE nameKey = ? AND teamClub = ?",
    params, Integer.class);

Offensichtlich macht diese Ablehnung die JdbcTemplate-Klasse einfacher (oder doch?). QueryForInt war immer eine bequeme Methode (denke ich) und gibt es schon lange. Warum wurde es entfernt? Der Code wird dadurch komplizierter.

Dan MacBean
quelle
Diese Details veralteten Methoden: static.springsource.org/spring/docs/current/javadoc-api/…
Dan MacBean
Sie haben Recht, ich weiß nicht, warum meine Quelle nicht hat@Deprecated
Sotirios Delimanolis
Aktualisiert die Spring-Version auf 3.2.2 - wie es scheint, ist es hier zuerst veraltet
Dan MacBean
Ich habe die vorhandene Codebasis von 3.1 auf 3.2.2 aktualisiert und diese Methoden werden überall verwendet. Sie müssen verstehen, warum und wie Sie den Code aktualisieren.
Dan MacBean
Beachten Sie, dass queryForObject zurückkehren kann null(in Ihrem Beispiel nicht der Fall). Ich habe keine andere Möglichkeit gefunden, als jetzt den Nullprüfcode von queryForInt / Long zu duplizieren.
hochraldo

Antworten:

109

Was ich denke ist, dass jemand erkannt hat, dass die queryForInt / Long-Methoden eine verwirrende Semantik haben, dh aus dem JdbcTemplate-Quellcode können Sie die aktuelle Implementierung sehen:

@Deprecated
public int queryForInt(String sql, Object... args) throws DataAccessException {
    Number number = queryForObject(sql, args, Integer.class);
    return (number != null ? number.intValue() : 0);
}

Dies kann zu der Annahme führen, dass die leere Ergebnismenge 0 zurückgibt, jedoch eine Ausnahme auslöst:

org.springframework.dao.EmptyResultDataAccessException: Incorrect result size: expected 1, actual 0

Die folgende Implementierung entspricht also im Wesentlichen der aktuellen:

@Deprecated
public int queryForInt(String sql, Object... args) throws DataAccessException {
    return queryForObject(sql, args, Integer.class);
}

Und dann muss der nicht veraltete Code jetzt durch den hässlichen ersetzt werden:

    queryForObject(sql, new Object { arg1, arg2, ...}, Integer.class);

oder das (schöner):

    queryForObject(sql, Integer.class, arg1, arg2, ...);
Gabriel Belingueres
quelle
12
Das stimmt nicht Das dritte Code-Snippet entspricht NICHT der Implementierung! Weil es eine versteckte NPE mit dem automatischen Unboxing gibt. Wenn Ihre Abfrage Ergebnisse zurückgibt, diese jedoch null sind, gibt der vorherige Code 0 anstelle von null zurück. Um das vorherige Verhalten ordnungsgemäß zu reproduzieren, lautet dies: Integer result = queryForObject (sql, args, Integer.class); Ergebnis zurückgeben == null? 0: Ergebnis;
MetroidFan2002
@ MetroidFan2002: In der Tat ist Ihre Beobachtung wahr! Unter dem Gesichtspunkt des API-Entwurfs ist es jedoch meiner Meinung nach besser, wenn die Abfrage nur einen NULL-Wert zurückgibt, ihn unverändert zurückzugeben, anstatt zu summieren, dass (wie queryForInt) ein NULL-Wert gleich 0 ist. Dies ist der Job des API-Benutzers, um diese Art von Bedingungen zu bewerten.
Gabriel Belingueres
Das Problem ist, dass, wenn ein Benutzer dort eine NPE erhält, die NPE in dieser Zeile wie die JDBCOperations-Instanz aussieht, sofern er bestimmte Dinge nicht explizit in seiner Umgebung eingerichtet hat (z. B. hat Eclipse die Option, die Verwendung von Autoboxing hervorzuheben) ist Null. Zuvor wäre Null zurückgegeben worden. Nun, warum Sie dies in einer Abfrage verwenden würden, die null zurückgibt, weiß ich nicht (dies liegt im Grunde daran, dass n00bs es tun, was sie tun werden), aber diese wegzunehmen ist IMO kein großer Schritt.
MetroidFan2002
Ich fand einen möglichen Grund in der Ungenauigkeit. Ich hatte einen langen Wert von 10000000233174211, der von queryForLong (String) zurückgegeben wurde, aber stattdessen 10000000233174212. dh +1. Ich habe im Code nachgesehen und er konvertiert ein Double in ein Long. Vielleicht gibt es ein Problem mit der Konvertierung.
Frau Wadge
Wenn ich etwas weiter oben über meinen Kommentar nachdenke, war der Datentyp für die Spalte die Nummer (19,0). Vielleicht kam deshalb Double ins Spiel? Ich habe das Problem sowieso mit queryForObject (sql, Long.class) umgangen.
Frau Wadge
35

Ich stimme dem Originalposter zu, dass die Ablehnung der Convenience-Methode queryForLong (sql) eine Unannehmlichkeit darstellt.

Ich hatte eine App mit Spring 3.1 entwickelt und gerade auf die neueste Spring-Version (3.2.3) aktualisiert und festgestellt, dass sie veraltet war.

Zum Glück war es eine einzeilige Änderung für mich:

return jdbcTemplate.queryForLong(sql);  // deprecated in Spring 3.2.x

wurde geändert in

return jdbcTemplate.queryForObject(sql, Long.class);

Und ein paar Unit-Tests scheinen darauf hinzudeuten, dass die obige Änderung funktioniert.

SGB
quelle
guter Punkt. Es würde auch ohne die Klammer gut funktionieren. :)
SGB
14

Veraltet zugunsten von queryForObject(String, Class).

vertti
quelle
13

Ersetzen eines solchen Codes:

long num = jdbcTemplate.queryForLong(sql);

Mit diesem Code:

long num = jdbcTemplate.queryForObject(sql, Long.class);

ist sehr gefährlich, denn wenn die Spalte einen Nullwert hat, gibt queryForObject null zurück und wie wir wissen, können primitive Typen nicht null sein, und Sie haben eine NullPointerException. Der Compiler hat Sie nicht davor gewarnt. Sie werden diesen Fehler zur Laufzeit kennen. Der gleiche Fehler, den Sie haben, wenn Sie eine Methode haben, die den primitiven Typ zurückgibt:

public long getValue(String sql) {
    return = jdbcTemplate.queryForObject(sql, Long.class);
}

Die veraltete Methode queryForLong in JdbcTemplate in Spring 3.2.2 hat den folgenden Text:

@Deprecated
public long queryForLong(String sql) throws DataAccessException {
    Number number = queryForObject(sql, Long.class);
    return (number != null ? number.longValue() : 0);
}

Sie sehen, bevor sie den primitiven Wert zurückgeben, wird überprüft, ob dies nicht null ist, und wenn es null ist, geben sie 0 zurück. Übrigens - Sollte 0L sein.

Marcin Kapusta
quelle
3
2 Cent: Der Compiler warnt Sie möglicherweise davor, wenn Sie die Autoboxing-Warnung aktiviert haben.
Keiki
Das wusste ich nicht. Danke Kumpel :)
Marcin Kapusta
2

JdbcTemplate#queryForIntGibt 0 zurück, wenn der Spaltenwert SQL NULL oder 0 ist. Es gibt keine Möglichkeit, einen Fall vom anderen zu unterscheiden. Ich denke, dies ist der Hauptgrund, warum die Methode veraltet ist. Übrigens ResultSet#getIntverhält sich ähnlich. Wir können diese beiden Fälle jedoch durch unterscheiden ResultSet#wasNull.

jddxf
quelle
-1
public int getCircleCount() {
    Object param = "1";
    String sql = "select count(*) from circle where id = ? ";
    jdbcTemplate.setDataSource(getDataSource());
    int result = getJdbcTemplate().queryForObject(sql, new Object[] { param }, Integer.class);
    return result;
}
Manikannan Arumugam
quelle
Bitte erläutern Sie Ihre Antwort.
Harsh Wardhan