Comme vous l’avez vu dans le Chapitre 14, “I/O,” il est important de fermer les ressources lorsque vous avez terminé de les utiliser. Cela est également vrai pour JDBC. Les ressources JDBC, comme une Connection
, sont coûteuses à créer. Ne pas les fermer crée une fuite de ressources qui finira par ralentir votre programme.
Tout au long du chapitre, nous avons utilisé la syntaxe try-with-resources du Chapitre 11. Les ressources doivent être fermées dans un ordre spécifique. Le ResultSet
est fermé en premier, suivi par le PreparedStatement
(ou CallableStatement
) puis la Connection
.
Bien qu’il soit recommandé de fermer ces trois ressources, ce n’est pas strictement nécessaire. La fermeture d’une ressource JDBC devrait fermer toutes les ressources qu’elle a créées. En particulier, les points suivants sont vrais :
- Fermer une
Connection
ferme égalementPreparedStatement
(ouCallableStatement
) etResultSet
. - Fermer un
PreparedStatement
(ouCallableStatement
) ferme également leResultSet
.
Il est important de fermer les ressources dans le bon ordre. Cela évite à la fois les fuites de ressources et les exceptions.
Écriture d’une Fuite de Ressources
Dans le Chapitre 11, vous avez appris qu’il est possible de déclarer un type avant une instruction try-with-resources. Voyez-vous pourquoi cette méthode est mauvaise ?
public void mauvaise() throws SQLException {
var url = "jdbc:hsqldb:zoo";
var sql = "SELECT pas_une_colonne FROM noms";
var conn = DriverManager.getConnection(url);
var ps = conn.prepareStatement(sql);
var rs = ps.executeQuery();
try (conn; ps; rs) {
while (rs.next())
System.out.println(rs.getString(1));
}
}
Supposons qu’une exception soit lancée à la ligne où executeQuery()
est appelé. Le bloc try-with-resources n’est jamais atteint, donc nous ne bénéficions pas de la fermeture automatique des ressources. Cela signifie que ce code a une fuite de ressources s’il échoue. N’écrivez pas de code comme celui-ci.
Il existe une autre façon de fermer un ResultSet
. JDBC ferme automatiquement un ResultSet
lorsque vous exécutez une autre instruction SQL à partir du même Statement
. Cela pourrait être un PreparedStatement
ou un CallableStatement
.
Gestion des Exceptions
Dans la majeure partie de ce chapitre, nous avons vécu dans un monde parfait. Certes, nous avons mentionné qu’une exception vérifiée SQLException
pourrait être lancée par n’importe quelle méthode JDBC, mais nous ne l’avons jamais attrapée. Nous l’avons simplement déclarée et laissé l’appelant s’en occuper. Maintenant, attrapons l’exception.
var sql = "SELECT pas_une_colonne FROM noms";
var url = "jdbc:hsqldb:zoo";
try (var conn = DriverManager.getConnection(url);
var ps = conn.prepareStatement(sql);
var rs = ps.executeQuery()) {
while (rs.next())
System.out.println(rs.getString(1));
} catch (SQLException e) {
System.out.println(e.getMessage());
System.out.println(e.getSQLState());
System.out.println(e.getErrorCode());
}
La sortie ressemble à ceci :
Column 'PAS_UNE_COLONNE' is either not in any table … 42X04 30000
Chacune de ces méthodes vous donne une information différente. La méthode getMessage()
renvoie un message lisible par l’homme sur ce qui s’est mal passé. Nous n’avons inclus que le début ici. La méthode getSQLState()
renvoie un code indiquant ce qui s’est mal passé. Vous pouvez rechercher sur Google le nom de votre base de données et l’état SQL pour obtenir plus d’informations sur l’erreur. En comparaison, getErrorCode()
est un code spécifique à la base de données. Sur cette base de données, il ne fait rien.