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 :

accès multi thread


Sujet :

JDBC Java

  1. #1
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179
    Par défaut accès multi thread
    Avant toute chose, bonne année à tous.

    J'ai un soucis depuis 3 semaines qui ressort sur une appli qui tourne depuis un an sans soucis, donc sans idées sur le pourquoi je vous le soumets.

    Symptomes:
    Depuis 3 semaines j'ai eu 3 crash d'index et une perte totale d'un fichier de données. Si j'avais un petit doute au début (après des mois de traitements sans incidents) je n'en ai plus, il y a un soucis qqpart.

    contexte :
    Une application sous java en multi thread qui utilise 2 tables MYSQL (5.0.27).
    Les tables sont super simples avec une dizaine de colonnes chacune.
    Chaque table a une classe dédiée métier qui s'occupe des requêtes.
    Des transactions arrivent par socket d'un système externe.
    Pour chacune d'elle un thread qui s'occupe d'effectuer un traitement approprié avec accès sur 2 tables (création/modification/..) est lancé.
    Plusieurs thread de traitement peuvent être lancés en même temps (si plusieurs transactions entrantes).
    Chaque thread de traitement instancie les 2 classes d'accès aux tables.
    Tout (semble) bien parallèle, bien protégé.
    Il y a une variable connection (jdbc) en globale static pour toute l'application initialisée dès le début.
    Cette connection est passée à chaque nouvelle instance de classe d'accès aux tables créée par les threads de traitement.
    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
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
     
    //skeleton COLUMN access TABLE
    public DBTx implements K
    {
      private Connection          cx          = NULL;
      private Statement           stm        = NULL;
     
      public DBTx (Connection connection) throws SQLException
      {
        cx = connection;
        IF (cx != NULL)
          stm = cx.createStatement();
      }
     
     String Get (String KEY)
     {
       Resultset rs=NULL
       String value="",query="";
       try
       {
          query="...";
          rs = stm.executeQuery(query);
          //traitement du rs ..
       }
       catch (SQLException e)
       {
       }
       finally
       {
         rs.close();
       }
       RETURN value;
     }
     
     String Process (String KEY)
     {
       Resultset rs=NULL
       String value="",query="";
       try
       {
          query="...";
          rs = stm.executeQuery(query);
          //traitement du rs ..
          ...
       }
       catch (SQLException e)
       {
       }
       finally
       {
         rs.close();
       }
       RETURN value;
     }
     
     BOOLEAN UPDATE (String KEY, String DATA[])
     {
       String query="";
       BOOLEAN ok=false;
       try
       {
          query="...";
          stm.executeUpdate(query, Statement.RETURN_GENERATED_KEYS); 
          ...
          ok=true;
       }
       catch (SQLException e)
       {
       }
       finally
       {
       }
       RETURN ok;
     }

    Chaque classe instanciée a en global une variable statement et en local à chaque méthode un resultset qui est fermé à la fin de chaque méthode.

    Le statement doit il être local à chaque méthode (ds le cas où 2 méthodes de la même classe sont appelées en même temps) ?
    Doit il être clôturé obligatoirement ?
    Comme c le driver qui gère les accès simultanés en lecture/création, seuls les update devraient être managés par des synchronized ou lock donc normalement quid des telescopages donc je suis dans le noir.

    Merci de votre aide et suggestion à tous.

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Citation Envoyé par r2d2abc Voir le message
    Tout (semble) bien parallèle, bien protégé.
    Il y a une variable connection (jdbc) en globale static pour toute l'application initialisée dès le début.
    chaque thread doit avoir sa propre connection à la base de donnée. L'objet connection de jdbc n'étant pas ThreadSafe. Il en va ainsi de même pour tous les objets découlant de la connection (Statement, resultset, transaction....).

  3. #3
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179
    Par défaut
    Salut et merci de ta réponse.

    Cela veut dire que pour un thread dont la durée de vie est de quelques ms je dois faire un DriverManager.getConnection(url) .. que tous les statements seront locaux à chaque méthode des classes .. ?
    c un pas un peu lourd ? je pensais que le niveau connection pouvait être le canal réutilisable de tous les statements..
    c pas très optimal non ? je peux avoir plusieurs (dizaines) de milliers de transactions par jour à traiter on peut pas mutualiser un peu les traitements et éviter une surcharge en déclarations ?

    thank's

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    la connection, ce n'est pas threadsafe, point. Maintenant tu as plusieurs possiilités au choix

    1) avoir un certains nombre de threads pour traiter tes demandes extérieures, ces thread auront chacun leur connection avec des statements préparés. Dans ce cas, t'as juste à réutiliser les Thread au lieu de les arreter. Ainsi ton application gardera, par exemple, une dixaine de connections en continu. Ce cas me semble intéressant dans ton cas car, non seulement on évitera de créer à chaque fois une connection, mais en plus on évitera de créer à chaque fois un thread, ce qui est aussi un processus lourd Le tout est de calibrer après la taille de ton pool de threads.

    2) utiliser un connection pool. Dans ce deuxième cas, tu crée pour chaque demande entrante un nouveau thread qui va aller demander une connection au pool. C'est ce dernier qui se chargera d'éviter de créer / fermer en continu des connections mais plutot de les réutiliser de manière propre.


    3) continuer a utiliser une seule connection, mais dans ce cas, utiliser des blocs synchronized autour de toutes tes transactions pour éviter les conflits -> solution qui va vite plomber tes performances, je pense...

  5. #5
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179
    Par défaut
    bon alors changement relativement profond de structure -> pas neutre (et surtout grosse erreur initiale) il va falloir faire attention car cette appli qui tourne en prod.
    je vais voir entre les 1° & 2° solution la plus optimale & la moins couteuse en terme de dev.
    Sur la question de déclarer un statement en global à la classe plutôt que local à chaque procédure je pense donc que tu es aussi pour la déclaration systématique en local non de chaque méthode non ?
    merci tchize

  6. #6
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Je ne suis pas tout à fait du même avis que tchize_, pour moi, en fonction du traitement à faire, on peut très bien partager l'objet Connection.
    Il n'en va pas de même avec l'objet Statement !
    Le plus sûr serait de mettre le traitement dans un bloc try catch finally et dans cette dernière, placer la fermeture du statement et du resultSet tant qu'à être propre (bien que la fermeture du statement entraine la fermeture du resultset)
    Les blocs de synchronisation sont gourmands en ressource système (surtout avec Windows) donc, si ce n'est pas utile, autant l'éviter.

    A toi de voir
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Je ne suis pas tout à fait du même avis que tchize_, pour moi, en fonction du traitement à faire, on peut très bien partager l'objet Connection.
    C'est ce que j'ai dit (cf deuxième post), mais la connection n'est pas threadsafe, il faut donc utiliser des bloc synchronized pour éviter les clash. Si on pouvais utiliser une connection jdbc depuis plusieurs threads sans synchronized, on s'emmerderait pas à faire des connection pool pour les webapp, on ferait une seule connection que tout le monde utiliserait. Et dans son cas, je pense, les blocs synchronized risquent de tuer ses performances.

  8. #8
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Ben c'est là que je ne te suis pas...
    Les connexions ne sont pas threadsafe, on est d'accord, mais ça ne veut pas dire qu'on ne peut pas les partager entre plusieurs thread du moment qu'on utilise un statement local.
    La seule contrainte que j'y vois serait liée au nombre de statement qu'on peu attacher à une connexion et qui dépend de la base et/ou du driver jdbc
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

  9. #9
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    ...
    Si on pouvais utiliser une connection jdbc depuis plusieurs threads sans synchronized, on s'emmerderait pas à faire des connection pool pour les webapp, on ferait une seule connection que tout le monde utiliserait
    ...
    Ben non, parce que justement il y a une problématique de nombre de statement et qu'en plus, il y a (très certainement) une notion de transaction.
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    Citation Envoyé par OButterlin Voir le message
    Ben c'est là que je ne te suis pas...
    Les connexions ne sont pas threadsafe, on est d'accord, mais ça ne veut pas dire qu'on ne peut pas les partager entre plusieurs thread du moment qu'on utilise un statement local.
    Je ne suis pas d'accord, l'API javadoc ne dit pas ca. Certe, chaque thread peut manipuler son statement, mais il faut etre logique, pour l'exécuter il faudra passer par la connection réseau sous jacente et, rien, autant que je sache, dans le jdbc, ne te dit que le driver est supposé faire gaffe au fait que la connection va etre utilisée par plusieurs statements au même moment!

    Je peux me tromper mais, moi, sans indication claire de la doc stipulant que des statements sortis d'une connection unique peuvent etre utilisés en parallèle sans prendre de précautions, je ne me risquerait pas a mettre en place un code qui peut sauter si on change de db, de version du driver ou meme qu'on patche la base de donnée...

    Si le driver ne prend aucune précaution à ce sujet (et je ne vois encore une fois pas de doc disant qu'il doit en prendre), on pourrait se retrouver avec de l'emmellage de paquet dans n'importe quel sens sur la couche réseau, sans parler des pointeurs de résultat qui pourraient se retrouver mélangés entre les statements. Le cas le plus heureux serait alors une rupture de la connection avec le serveur qui comprend rien à ce qu'on lui demande.

    Sans parler de la gestion de la transaction qui n'aurait plus aucun sens...

  11. #11
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179
    Par défaut
    bon tchize_ après réflexion sur le code de l'appli cet pm, je pense mettre en place un pool de connections réutilisables avec tous les statements et resultset associés en local sur la stack de chaque méthode de la classe instanciée.
    totale immunité et séparation des accès, je fais confiance au driver pour effectuer un multiplexage/démultiplexage des requêtes avec le moteur.
    c dingue qu'un défaut (limite majeur de dev) soit passé au travers pdt plusieurs mois de transactions processès sans pb quelconques.
    il faudra regarder le nb max connections utilisables par le jdbc pour ne pas déporter le pb sur un autre.
    2 dernières questions et je clos :
    1- est-ce que plusieurs statements pour une même connection peuvent être utilisés en même temps, on n'est pas obligé de jouer avec des synchronized ou de sérialiser j'espère ?
    2- la ref d'un bon livre (parmi tous ceux existants) à conseiller (o'reilyl,addison...) sur le dev java(c++) <-> jdbc (mysql) en anglais/ bien trappu pour faire le tour du truc rapidement et à fond .
    thank's par avance

  12. #12
    Modérateur
    Avatar de OButterlin
    Homme Profil pro
    Inscrit en
    Novembre 2006
    Messages
    7 313
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France

    Informations forums :
    Inscription : Novembre 2006
    Messages : 7 313
    Points : 9 529
    Points
    9 529
    Billets dans le blog
    1
    Par défaut
    Citation Envoyé par tchize_ Voir le message
    Je ne suis pas d'accord, l'API javadoc ne dit pas ca. Certe, chaque thread peut manipuler son statement, mais il faut etre logique, pour l'exécuter il faudra passer par la connection réseau sous jacente et, rien, autant que je sache, dans le jdbc, ne te dit que le driver est supposé faire gaffe au fait que la connection va etre utilisée par plusieurs statements au même moment!

    Je peux me tromper mais, moi, sans indication claire de la doc stipulant que des statements sortis d'une connection unique peuvent etre utilisés en parallèle sans prendre de précautions, je ne me risquerait pas a mettre en place un code qui peut sauter si on change de db, de version du driver ou meme qu'on patche la base de donnée...

    Si le driver ne prend aucune précaution à ce sujet (et je ne vois encore une fois pas de doc disant qu'il doit en prendre), on pourrait se retrouver avec de l'emmellage de paquet dans n'importe quel sens sur la couche réseau, sans parler des pointeurs de résultat qui pourraient se retrouver mélangés entre les statements. Le cas le plus heureux serait alors une rupture de la connection avec le serveur qui comprend rien à ce qu'on lui demande.

    Sans parler de la gestion de la transaction qui n'aurait plus aucun sens...
    J'utilise (et d'autres aussi) plusieurs statement sur une même connexion en permanence, il n'y a aucun problème.
    Et je ne vois pas le rapport avec une autre DB.
    Le seul problème est lié aux transaction, là, on est d'accord...
    Si chaque statement abouti à un commit/rollback, il va de soit qu'on ne peut pas partager la connexion, mais si on doit faire de la lecture, aucun problème.
    Pour ce qui est du mélange des résultats, alors là, désolé mais c'est n'importe quoi... le ResultSet est avant tout lié à la requête (statement).
    Un exemple classique est une lecture de table imbriquée dans une boucle de lecture d'une table, tu ne vas pas me dire que tu utilises 2 connexions tout de même ?
    N'oubliez pas de consulter les FAQ Java et les cours et tutoriels Java

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

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

    Informations forums :
    Inscription : Avril 2007
    Messages : 25 482
    Points : 48 807
    Points
    48 807
    Par défaut
    j'ai jamaisdit que tu pouvais pas utiliser plusieurs statements sur une seule connection, ce que tu ne peux pas faire, c'est le faire depuis des thread séparés sans protection, au risque que ces statement, si exécuté en même temps, se battent pour la connection et la foutent en l'air car, on est clair là dessus, la connection n'est pas thread safe!

    C'est une chose de lire plusieurs table de manière imbriquée (et non je fais pas une deuxième connection pour ca) c'est un autre d'avoir 15 statement qui au même moment demandent au driver d'emmetre une requete sur la couche réseau, alors que justement la connection a pas été prévue pour être appelé en parallèle depuis plusieurs thread. Encore une fois, en java si l'api ne dit pas explicitement que les méthodes sont threadsafe, elles doivent être supposées ne pas l'être. Et ne pas avoir de problème n'est pas une preuve que tu n'en aura pas dans le futur, si la charge augment ou que tout d'un coup du doit faire 50 requetes en // sur la même demi seconde, tu risque les bugs obscurs.

    En ce qui me concerne, pas de doc explicite qui dit que c'est threadsafe -> jamais je n'accède à une connection depuis plusieurs thread sans protection!

  14. #14
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179
    Par défaut
    c plus que clair et logique maintenant.... thank's à tous les deux ..

  15. #15
    Membre habitué Avatar de r2d2abc
    Profil pro
    Inscrit en
    Janvier 2009
    Messages
    212
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Janvier 2009
    Messages : 212
    Points : 179
    Points
    179

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

Discussions similaires

  1. Multi thread accès variable
    Par untipy dans le forum Embarqué
    Réponses: 5
    Dernier message: 24/03/2015, 08h09
  2. [Multi-thread] Comment lock l'acces a un containeur de la STL ?
    Par Izidor's dans le forum Threads & Processus
    Réponses: 5
    Dernier message: 14/10/2009, 12h09
  3. [EF] Accès multi thread
    Par dev01 dans le forum Accès aux données
    Réponses: 27
    Dernier message: 27/03/2009, 15h08
  4. Tri multi-threadé
    Par Tifauv' dans le forum C
    Réponses: 8
    Dernier message: 28/06/2007, 09h00
  5. [Kylix] exception qtinft.dll et multi-threading
    Par leclaudio25 dans le forum EDI
    Réponses: 3
    Dernier message: 27/03/2003, 18h09

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