JdbcTemplate queryForInt / Long est obsolète dans Spring 3.2.2. Par quoi devrait-il être remplacé?

104

Les méthodes queryforInt / queryforLong dans JdbcTemplate sont obsolètes dans Spring 3.2. Je ne peux pas savoir pourquoi ni ce qui est considéré comme la meilleure pratique pour remplacer le code existant à l'aide de ces méthodes.

Une méthode typique:

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

OK, la méthode ci-dessus doit être réécrite comme suit:

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

De toute évidence, cette dépréciation rend la classe JdbcTemplate plus simple (ou est-ce le cas?). QueryForInt a toujours été une méthode pratique (je suppose) et existe depuis longtemps. Pourquoi a-t-il été supprimé. Le code devient par conséquent plus compliqué.

Dan MacBean
la source
Ce détail des méthodes obsolètes: static.springsource.org/spring/docs/current/javadoc-api/…
Dan MacBean
Vous avez raison, je ne sais pas pourquoi ma source n'a pas@Deprecated
Sotirios Delimanolis
Mise à jour de la version Spring à 3.2.2 - car il semble qu'elle est d'abord obsolète ici
Dan MacBean
J'ai mis à niveau la base de code existante de 3.1 à 3.2.2 et ces méthodes sont utilisées partout. Besoin de comprendre pourquoi et comment mettre à jour le code.
Dan MacBean
Sachez que queryForObject peut retourner null(pas le cas dans votre exemple). Je n'ai trouvé d'autre moyen que de dupliquer maintenant le code de vérification nul de queryForInt / Long.
hochraldo

Réponses:

110

Ce que je pense, c'est que quelqu'un s'est rendu compte que les méthodes queryForInt / Long ont une sémantique déroutante, c'est-à-dire qu'à partir du code source de JdbcTemplate, vous pouvez voir son implémentation actuelle:

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

ce qui peut vous amener à penser que si le jeu de résultats est vide, il renverra 0, mais il lève une exception:

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

donc l'implémentation suivante est essentiellement équivalente à l'actuelle:

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

Et puis le code non obsolète doit maintenant être remplacé par le laid:

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

ou ceci (mieux):

    queryForObject(sql, Integer.class, arg1, arg2, ...);
Gabriel Belingueres
la source
12
Ce n'est pas vrai. Le troisième extrait de code n'est PAS égal à l'implémentation! Parce qu'il y a un NPE caché avec le déballage automatique. Si votre requête retournait des résultats, mais qu'ils étaient nuls, le code précédent renverrait 0 au lieu de null - pour reproduire correctement le comportement précédent, ce serait: Integer result = queryForObject (sql, args, Integer.class); retourne le résultat == null? 0: résultat;
MetroidFan2002
@ MetroidFan2002: En effet, votre observation est vraie! Cependant, du point de vue de la conception de l'API, si la requête ne renvoie qu'une valeur NULL, je pense qu'il est préférable de la renvoyer telle quelle, au lieu de supposer que (comme le fait queryForInt) un NULL est équivalent à 0. C'est le travail de l'utilisateur de l'API pour évaluer ce type de conditions.
Gabriel Belingueres
Le problème est que si et quand un utilisateur obtient un NPE là-bas, à moins qu'il ne configure explicitement certaines choses dans son environnement (par exemple, Eclipse a une option pour mettre en évidence les utilisations de la boîte automatique), le NPE sur cette ligne ressemblera à l'instance JDBCOperations est nul. Auparavant, zéro aurait été renvoyé. Maintenant, pourquoi vous utiliseriez cela dans une requête qui renvoie null, je n'en ai aucune idée (c'est essentiellement dû au fait que n00bs le fait, ce qu'ils feront), mais les retirer n'est pas un grand pas IMO.
MetroidFan2002
J'ai trouvé une raison possible à cause de l'inexactitude. J'avais une valeur longue de 10000000233174211 renvoyée par queryForLong (String), mais à la place, elle retournait 10000000233174212. ie +1. J'ai regardé dans le code et il convertit un Double en Long, donc peut-être qu'il y a un problème avec la conversion.
mrswadge
En pensant un peu plus à mon commentaire ci-dessus, le type de données pour la colonne était le numéro (19,0), alors peut-être est-ce pourquoi le double est entré en jeu? J'ai contourné le problème en utilisant de toute façon queryForObject (sql, Long.class).
mrswadge du
35

Je suis d'accord avec l'affiche originale que déconseiller la méthode de commodité queryForLong (sql) est un inconvénient.

J'avais développé une application utilisant Spring 3.1 et je venais de la mettre à jour avec la dernière version Spring (3.2.3) et j'ai remarqué qu'elle était obsolète.

Heureusement, c'était un changement d'une ligne pour moi:

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

a été changé en

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

Et quelques tests unitaires semblent indiquer que le changement ci-dessus fonctionne.

SGB
la source
bon point. Cela fonctionnerait bien sans les parenthèses aussi. :)
SGB
14

Déconseillé au profit de queryForObject(String, Class).

vertti
la source
13

Remplacement de ce code:

long num = jdbcTemplate.queryForLong(sql);

Avec ce code:

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

est très dangereux car si la colonne a une valeur nulle, queryForObject renvoie null et comme nous le savons, les types primitifs ne peuvent pas être nuls et vous aurez NullPointerException. Le compilateur ne vous a pas averti à ce sujet. Vous connaîtrez cette erreur lors de l'exécution. La même erreur que vous aurez si vous avez une méthode qui renvoie le type primitif:

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

La méthode obsolète queryForLong dans JdbcTemplate dans Spring 3.2.2 a le corps suivant:

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

Vous voyez avant qu'ils ne retournent la valeur primitive, il est vérifié que ce n'est pas nul et s'il est nul, ils retournent 0. Au fait - Doit être 0L.

Marcin Kapusta
la source
3
2 centimes: Le compilateur peut vous en avertir si vous avez activé l'avertissement de détection automatique.
keiki
Je n'en savais rien. Thanks mate :)
Marcin Kapusta
2

JdbcTemplate#queryForIntrenvoie 0 si la valeur de la colonne est SQL NULL ou 0. Il n'y a aucun moyen de distinguer un cas de l'autre. Je pense que c'est la principale raison pour laquelle la méthode est obsolète. BTW, ResultSet#getIntse comporte de la même manière. Cependant, nous pouvons distinguer ces deux cas par ResultSet#wasNull.

jddxf
la source
-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
la source
Veuillez expliquer votre réponse.
Harsh Wardhan