Fermeture des connexions JDBC dans le pool

109

Notre section de code standard pour l'utilisation de JDBC est ...

Connection conn = getConnection(...);
Statement  stmt = conn.conn.createStatement (ResultSet.TYPE_SCROLL_INSENSITIVE,
                                                ResultSet.CONCUR_READ_ONLY);
ResultSet  rset = stmt.executeQuery (sqlQuery);

// do stuff with rset

rset.close(); stmt.close(); conn.close();

Question 1: Lors de l'utilisation du pool de connexions, faut-il fermer la connexion à la fin? Si tel est le cas, l'objectif de la mise en commun n'est-il pas perdu? Et sinon, comment DataSource sait-il quand une instance particulière de Connection est libérée et peut être réutilisée? Je suis un peu confus sur celui-ci, tous les pointeurs sont appréciés.

Question 2: La méthode suivante est-elle proche de la norme? Ressemble à une tentative d'obtenir une connexion à partir du pool, et si DataSource ne peut pas être établi, utilisez l'ancien DriverManager. Nous ne savons même pas quelle partie est exécutée au moment de l'exécution. En répétant la question ci-dessus, faut-il fermer la connexion en sortant d'une telle méthode?

Merci, - MS.

synchronized public Connection getConnection (boolean pooledConnection)
                                                        throws SQLException {
        if (pooledConnection) {
                if (ds == null) {
                        try {
                                Context envCtx = (Context)
                                        new InitialContext().lookup("java:comp/env");
                                ds = (DataSource) envCtx.lookup("jdbc/NamedInTomcat");
                                return ds.getConnection();
                        } catch (NamingException e) {
                                e.printStackTrace();
                }}
                return (ds == null) ? getConnection (false) : ds.getConnection();
        }
        return DriverManager.getConnection(
                "jdbc:mysql://"+ipaddy+":"+dbPort +"/" + dbName, uName, pWord);
}

Edit: Je pense que nous obtenons la connexion groupée car nous ne voyons pas de trace de pile.

Manidip Sengupta
la source

Réponses:

121

Lorsque vous utilisez Connection Pool, doit-on fermer la connexion à la fin? Si tel est le cas, l'objectif de la mise en commun n'est-il pas perdu? Et sinon, comment DataSource sait-il quand une instance particulière de Connection est libérée et peut être réutilisée? Je suis un peu confus sur celui-ci, tous les pointeurs sont appréciés.

Oui, vous devez certainement également fermer la connexion groupée. C'est en fait un wrapper autour de la connexion réelle. Sous les couvertures, la connexion réelle à la piscine sera libérée. C'est au pool de décider si la connexion réelle sera effectivement fermée ou réutilisée pour un nouvel getConnection()appel. Ainsi, que vous utilisiez ou non un pool de connexions, vous devez toujours fermer toutes les ressources JDBC dans l'ordre inverse dans le finallybloc du trybloc où vous les avez acquises. Dans Java 7, cela peut être encore simplifié en utilisant try-with-resourcesstatement.


La méthode suivante est-elle proche de la norme? Ressemble à une tentative d'obtenir une connexion à partir du pool, et si DataSource ne peut pas être établi, utilisez l'ancien DriverManager. Nous ne savons même pas quelle partie est exécutée au moment de l'exécution. En répétant la question ci-dessus, faut-il fermer la connexion en sortant d'une telle méthode?

L'exemple est assez effrayant. Il vous suffit de rechercher / initialiser la DataSourceseule fois lors du démarrage de l'application dans un constructeur / initialisation d'une classe de configuration de base de données à l'échelle de l'application. Ensuite, appelez simplement getConnection()la même source de données pendant toute la durée de vie de l'application. Pas besoin de synchronisation ni de nullchecks.

Voir également:

BalusC
la source
C'est ce qu'il fait (initialiser une fois), n'est-ce pas? ds est une variable d'instance, et if (ds == null) ... est la partie d'initialisation.
Manidip Sengupta
Faire les vérifications à chaque fois dans une méthode get comme getConnection()c'est bizarre. Faites-le simplement dans c'tor ou dans un bloc d'initialisation de la même classe, sans synchronisation / nullchecks. Il ne sera appelé qu'une seule fois. Pour plus de conseils et d'exemples de lancement, cet article peut vous être utile.
BalusC
Excellent article, BalusC. La classe avec laquelle je travaille implémente à peu près la couche de données, en utilisant des DTO. Je suis d'accord avec vous, l'initialisation doit être dans le constructeur. Maintenant, cette classe a une tonne de méthodes, chacune avec conn, stmt et rset comme variables locales, les connexions sont dans un bloc try, et enfin il y a un appel à une ligne csrClose (conn, stmt, rset), où les 3 sont fermés (dans l'ordre inverse). Désormais, le DTO que vous développez dans l'exemple est une image miroir d'une ligne de table DB. Nous avons des requêtes SQL complexes avec des jointures (et d'autres clauses), avez-vous un article sur la façon de développer des DAO pour de tels résultats?
Manidip Sengupta
2
@yat: Vous DEVEZ les appeler close()tous dans le finallybloc du même trybloc que celui où vous les avez acquis / créés. Ceci est totalement indépendant du fait qu'il s'agisse d'une connexion groupée ou non.
BalusC
1
@iJava: cette piscine est écrite par un amateur qui n'a aucune idée de ce qu'il fait. Ignorez-le et optez pour une vraie bibliothèque. Par exemple HikariCP.
BalusC
22

Les pools vous renvoient généralement un objet Connection encapsulé, où la méthode close () est remplacée, renvoyant généralement la Connection au pool. L'appel de close () est OK et probablement toujours nécessaire.

Une méthode close () ressemblerait probablement à ceci:

public void close() throws SQLException {
  pool.returnConnection(this);
}

Pour votre deuxième question, vous pouvez ajouter un enregistreur pour montrer si le bloc inférieur s'exécute jamais. J'imagine que vous ne voudriez que d'une manière ou d'une autre pour la configuration de vos connexions de base de données. Nous utilisons uniquement un pool pour nos accès à la base de données. Dans tous les cas, la fermeture de la connexion serait très importante pour éviter les fuites.

taer
la source
Je suis d'accord, nous avons un enregistreur, et cela pourrait être utilisé ici aussi. J'ai besoin d'étudier un peu comment vous pouvez envelopper un objet, remplacer sa méthode close () tout en conservant le même nom de classe (Connection)
Manidip Sengupta
1
Calling close() is OK and probably still required., ne pas appeler close entraînera une fuite de la connexion, à moins que le pool
n'implémente
0

En fait, la meilleure approche de la gestion des connexions est de ne pas les restreindre à un code n'importe où.

Créez une classe SQLExecutor qui est le seul et unique emplacement qui ouvre et ferme les connexions.

L'ensemble du reste de l'application pompe ensuite les instructions dans l'exécuteur plutôt que d'obtenir des connexions du pool et de les gérer (ou de les mal gérer) partout.

Vous pouvez avoir autant d'instances de l'exécuteur que vous le souhaitez, mais personne ne doit écrire de code qui ouvre et ferme les connexions en son propre nom.

De manière pratique, cela vous permet également de consigner tous vos SQL à partir d'un seul ensemble de code.

Rodney P. Barbati
la source