IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

JDBC Java Discussion :

[Prepared Statement] Prepared statements toujours ouverts même après le commit


Sujet :

JDBC Java

  1. #1
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut [Prepared Statement] Prepared statements toujours ouverts même après le commit
    Bonjour à toutes et à tous,

    J'ai une application web (java) qui me permet d'insérer des données dans la base.

    Quelque soit le nombre de lignes insérées, après le commit, il y a toujours des prepared statements ouverts.

    Du coup, en essayant d'inserer un nombre important de lignes, au bout d'un moment l'application plante et j'ai l'erreur "ORA-01000: nombre maximum de curseurs ouverts dépassé" dans la console de mon IDE.

    Quelqu'un pourra m'expliquer dans quels cas les prepared statements peuvent rester ouverts, sachant que je les ferme dans le finally de mon code (preparedStatement.close()) ?

    Merci.

  2. #2
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Points : 2 061
    Points
    2 061
    Par défaut
    bonjour,

    s'ils restent ouvert c'est que tu ne les ferme pas tous !
    Sauf que sans ton code, difficile de savoir ou est le problème.
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  3. #3
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut
    Salut,

    Le code est très compliqué, on parle ici de plusieurs dizaines de classes et des milliers de lignes de code. J'ai vérifié pour quasiment toutes les méthodes appelées lors de la recherche, l'insertion et la modification, les preparedStatements sont fermés dans tous les blos finally.

    J'ai quelques questions :
    1. Si je ferme ma connexion alors que j'ai oublié de fermer mon preparedStatement, il restera toujours ouvert ou bien il se ferme ? (comme le cas pour le resultSet vis-à-vis le preparedStatement).

    2. connaissez-vous une méthode "rapide" permettant de detecter des preparedStatements ouverts et non fermés ?

    Merci

  4. #4
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Salut,

    Citation Envoyé par JQueen Voir le message
    J'ai vérifié pour quasiment toutes les méthodes appelées lors de la recherche, l'insertion et la modification, les preparedStatements sont fermés dans tous les blos finally.
    Montre nous au moins un exemple de code, qu'on puisse vérifier qu'il n'y ait pas de soucis...


    Sinon :
    1. Pas forcément.
    Sauf erreur de ma part, si tu utilises un pool de Connection la méthode close() ne ferme pas vraiment la Connection, mais la remet simplement dans le pool.
    Il est donc possible que les Statements ouvert le reste...


    2. Les EDIs peuvent générer un warning à la compilation.


    a++

  5. #5
    Expert éminent sénior
    Avatar de tchize_
    Homme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Avril 2007
    Messages
    25 481
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 44
    Localisation : Belgique

    Informations professionnelles :
    Activité : Ingénieur développement logiciels
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 481
    Points : 48 806
    Points
    48 806
    Par défaut
    Au passage les curseurs sont liés au ResultSet, pas au preparedStatement. Tu ferme bien tous les ResultSet? Le message peut aussi venir d'un procédure stockée oracle qui ne libèrerait pas son curseur. Comme les connexion sont réutilisées en java, le curseur ne sera jamais libéré.

  6. #6
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut
    @adiGuba

    voilà un exemple de code :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
     
                    Connection connexion = null;
    		ResultSet rs = null;
    		String sql = "";
    		PreparedStatement st = null;
    		String niveauProcedureTp = null;
     
    		try
    		{
    			connexion = getFournisseurInstance().ouvrirConnexion();
    			sql = "select  * from dossier";
     
    			st = connexion.prepareStatement(sql);
     
    			rs = st.executeQuery();
    			if (rs.next())
    			{
    				niveauProcedureTp = rs.getString("dossier");
    			}
    			return niveauProcedureTp;
    		}
    		catch (SQLException exception)
    		{
    			log.error("Requete : " + sql);
    			throw new LectureException("msg : " , exception);
    		}
    		catch (NamingException exception)
    		{
    			log.error("Requete : " + sql);
    			throw new LectureException(" msg: " , exception);
    		}
    		finally
    		{
    			getFournisseurInstance().fermerResultSet(rs);
    			getFournisseurInstance().fermerStatement(st);
    			getFournisseurInstance().fermerConnexion(connexion);
    		}

  7. #7
    Expert éminent sénior
    Avatar de adiGuba
    Homme Profil pro
    Développeur Java/Web
    Inscrit en
    Avril 2002
    Messages
    13 938
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations professionnelles :
    Activité : Développeur Java/Web
    Secteur : Transports

    Informations forums :
    Inscription : Avril 2002
    Messages : 13 938
    Points : 23 190
    Points
    23 190
    Billets dans le blog
    1
    Par défaut
    Il manque encore le code de tes méthodes fermerResultSet(), fermerStatement() et fermerConnexion(), mais il est probable qu'une exception dans ces méthodes empêche les ressources suivantes d'être fermées.
    En plus les déclarations à null en début de code n'aide pas...

    Perso j'éviterais de faire trop de chose dans le finally, car le moindre problème empêchera la libération des autres ressources.

    Pre-Java 7 le pattern correct pour la libération des ressources est le suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    Ressource res = createRessource();
    try {
        // code ICI
    } finally {
        res.close();
    }
    Mais le plus important c'est qu'il faut utiliser cela pour chaque ressource.
    Il ne faut surtout pas regrouper tout dans un seul finally : chaque ressource doit avoir le sien.
    Et si l'on doit traiter les exceptions, il est préférable d'avoir un try/catch qui englobe le tout.

    Ce qui donnerait :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    		try {
    			final Connection connexion = getFournisseurInstance().ouvrirConnexion();
    			try {
    				final String sql = "select  * from dossier";
    				final PreparedStatement st = connexion.prepareStatement(sql);
    				try {
    					final ResultSet rs = st.executeQuery();
    					try {
    						String niveauProcedureTp = null;
    						if (rs.next()) {
    							niveauProcedureTp = rs.getString("dossier");
    						}
    						return niveauProcedureTp;
    					} finally {
    						rs.close();
    					}
    				} finally {
    					st.close();
    				}
    			} finally {
    				connexion.close();
    			}
    		} catch (SQLException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException("msg : ", exception);
    		} catch (NamingException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException(" msg: ", exception);
    		}


    Bien sûr à partir de Java 7 on utilisera plutôt le try-with ressources qui gère cela très bien dans tous les cas :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    		final String sql = "select  * from dossier";
    		try (final Connection connexion = getFournisseurInstance().ouvrirConnexion();
    			final PreparedStatement st = connexion.prepareStatement(sql);
    			final ResultSet rs = st.executeQuery() ) {
     
    				String niveauProcedureTp = null;
    				if (rs.next()) {
    					niveauProcedureTp = rs.getString("dossier");
    				}
    				return niveauProcedureTp;
    		} catch (SQLException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException("msg : ", exception);
    		} catch (NamingException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException(" msg: ", exception);
    		}


    a++

  8. #8
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
     
    final String sql = "select  * from dossier";
    		try (final Connection connexion = getFournisseurInstance().ouvrirConnexion();
    			final PreparedStatement st = connexion.prepareStatement(sql);
    			final ResultSet rs = st.executeQuery() ) {
     
    				String niveauProcedureTp = null;
    				if (rs.next()) {
    					niveauProcedureTp = rs.getString("dossier");
    				}
    				return niveauProcedureTp;
    		} catch (SQLException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException("msg : ", exception);
    		} catch (NamingException exception) {
    			log.error("Requete : " + sql);
    			throw new LectureException(" msg: ", exception);
    		}
    Dans ce code, il y a plus le bloc "finally", à quel niveau alors ferme-t-on les ressources ?

  9. #9
    Modérateur
    Avatar de Alkhan
    Homme Profil pro
    ingénieur full stack
    Inscrit en
    Octobre 2006
    Messages
    1 232
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Haute Garonne (Midi Pyrénées)

    Informations professionnelles :
    Activité : ingénieur full stack

    Informations forums :
    Inscription : Octobre 2006
    Messages : 1 232
    Points : 2 061
    Points
    2 061
    Par défaut
    bonjour,
    Citation Envoyé par JQueen Voir le message
    Dans ce code, il y a plus le bloc "finally", à quel niveau alors ferme-t-on les ressources ?
    comme indiqué par @adiGuba c'est le try-with ressources qui gère la fermeture des instances qui sont déclaré entre parenthèses !
    Il n'y a pas de problème, il n'y a que des solutions.
    Cependant, comme le disaient les shadoks, s'il n'y a pas de solution, c'est qu'il n'y a pas de problème.
    Si toutefois le problème persiste, la seule solution restante est de changer le périphérique qui se trouve entre la chaise et l'écran

    Mes Articles : Mon premier article est sur le language D
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  10. #10
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut
    voilà le code de la méthode de fermeture du resutlSet (pareil pour les deux autres méthodes) :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
     
    public final void fermerResultSet(ResultSet rs)
        {
            try
            {
                if (rs != null)
                {
                    rs.close();
                }
            }
            catch (SQLException exception)
            {
                log.warn("msg : ", exception);
            }
        }

  11. #11
    Membre habitué Avatar de JQueen
    Inscrit en
    Octobre 2008
    Messages
    214
    Détails du profil
    Informations personnelles :
    Âge : 37

    Informations forums :
    Inscription : Octobre 2008
    Messages : 214
    Points : 126
    Points
    126
    Par défaut
    Salut,

    J'ai du vérifier pour toutes les classes utilisant des preparedStatement/ResultSet la fermeture ou non de ces derniers.

    effectivement, il y avait des oublis dans certains bouts de code.

    Merci pour toutes vos remarques et votre aide

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 15/11/2014, 13h03
  2. [VBA] Excel toujours ouvert après traitement
    Par Trinou dans le forum SDK
    Réponses: 1
    Dernier message: 24/11/2009, 11h03
  3. Réponses: 1
    Dernier message: 20/08/2007, 17h22
  4. Réponses: 4
    Dernier message: 12/06/2003, 21h42

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo