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 :

[JDBC / DAO] Comment utiliser intelligemment le JNDI et JDBC?


Sujet :

JDBC Java

  1. #1
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2006
    Messages : 87
    Points : 38
    Points
    38
    Par défaut [JDBC / DAO] Comment utiliser intelligemment le JNDI et JDBC?
    Bonjour à tous,

    Je ne sais pas si je suis dans la bonne section, mais bon, je tente quand même.

    Je développe une application web en JSF 2.2/Tomcat 7 qui se connecte à un Mysql. Cette dernière utilise une cinquantaine de DAOs fait maison qui sont en scope APPLICATION.
    Ces DAOs hérite tous d'une classe BaseDao dans laquelle est initié la connexion à la base de données d'une manière assez dégueulasse et qui, je pense, peut poser pas mal de problème de performances:

    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
     
    public abstract class BaseDao implements Serializable {
     
        private transient static Connection connection;
     
        static {
            try {
                Context initCtx = new InitialContext();
                DataSource ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/db");
                connection = ds.getConnection();
            } catch (NamingException ex) {
            } catch (SQLException ex) {
            }
        }
        protected Connection con;
        protected transient final ResourceBundle requests;
        protected transient final Logger log = Logger.getLogger(BaseDao.class);
        protected transient final ResourceBundle msg = ResourceBundle.getBundle("msg");
     
        public BaseDao() throws SQLException {
            this.requests = ResourceBundle.getBundle("requests");
            this.con = BaseDao.connection;
        }
     
        protected PreparedStatement prepareStatement(final String requestName) throws SQLException {
            checkConnection();
            return con.prepareStatement(requests.getString(requestName));
        }
     
        protected PreparedStatement prepareRawStatement(final String request) throws SQLException {
            checkConnection();
            return con.prepareStatement(request);
        }
     
        protected PreparedStatement prepareStatementReturnId(final String requestName) throws SQLException {
            checkConnection();
            return con.prepareStatement(requests.getString(requestName), Statement.RETURN_GENERATED_KEYS);
        }
     
        private void checkConnection() throws SQLException {
            if (this.con == null) {
                this.con = getConnection();
            }
        }
     
        private Connection getConnection() throws SQLException {
            DataSource ds;
            try {
                Context initCtx = new InitialContext();
                ds = (DataSource) initCtx.lookup("java:comp/env/jdbc/db");
                return ds.getConnection();
            } catch (NamingException ex) {
                return null;
            }
     
        }
    }
    En gros, il y a UNE connexion pour toute l'application.

    Comment devrais-je procéder pour optimiser tout ça? Une connexion par DAO (en augmentant la taille du pool dans le JNDI et le nombre de connexions max autorisés dans Mysql?). Dois-je plutot faire pour chaque méthode de mes DAOs un DataSource.getConnection et fermer la connexion en fin de méthode? Peut-être existe-t-il un tutorial "bonnes pratiques" à propos de ce que je veux faire?

    Merci pour votre aide

  2. #2
    Expert confirmé
    Profil pro
    Inscrit en
    Août 2006
    Messages
    3 274
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Août 2006
    Messages : 3 274
    Points : 4 141
    Points
    4 141
    Par défaut
    Une connexion JDBC ne doit pas être partagée par plusieurs threads.
    Si une action utilisateur = un thread, il te faut une connexion tout le long de cette action, que tu fermeras à la fin de l'action pour la rendre au pool.
    Tu peux mettre en place une couche service, au dessus de tes DAOs.
    Chaque méthode du service peut regrouper n appels à des méthodes de DAOs.
    La connexion est créée au début de l'appel de la méthode et fermée à la fin.
    Tu peux stocker cette connexion au sein d'un ThreadLocal par exemple.

  3. #3
    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
    D'accord avec fr1man

    J'ai du mal à comprendre l'architecture de ton application, mettre des DAO dans un scope application, c'est du jamais vu pour moi
    Comment gères-tu la synchronisation des requêtes entre plusieurs utilisateurs ?

    Dans le principe, pour une application web, c'est bien au niveau request/response que ce font l'acquisition et la libération de(s) connexion(s).
    Il pourrait être judicieux de faire une petite classe utilitaire pour ça...
    Avec une couche DAO, j'aurais même fourni la connexion aux méthodes des DAO, plus simple dans le cas d'un traitement type "facade"

  4. #4
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2006
    Messages : 87
    Points : 38
    Points
    38
    Par défaut
    Merci pour vos réponses.

    J'avoue ne pas être super au point la dessus.

    Les Dao doivent donc être en scope request? Donc pour chaque requête, on aura une instanciation du Dao, et donc une acquisition de connexion?
    Je pensais que niveau performance ça allait être moyen.

  5. #5
    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
    Les DAO sont plutôt des classes utilitaires orientées "accès données" et qui sont appelées par ton contrôleur (par exemple).

    Tu peux implémenter le patter singleton pour limiter le nombre d'instances... (perso, c'est ce que j'utilise quand il n'y a pas d'EJB)
    Ensuite, passer la connexion en paramètre ou la prendre dans la DAO est une autre affaire.
    Si tu la passes, tu pourras faire plus de choses, par exemple gérer facilement des sous-transactions...
    Si tu la prends dans la DAO, tu peux utiliser le ThreadLocal pour la partager

  6. #6
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2006
    Messages : 87
    Points : 38
    Points
    38
    Par défaut
    Merci beaucoup.

    Je ne connaissais pas le ThreadLocal, je vais regarder ça de plus près.
    Ou alors réfléchir a changer toute l'architecture...

  7. #7
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2006
    Messages : 87
    Points : 38
    Points
    38
    Par défaut
    Du coup, je me demande un truc:

    Actuellement, mes controllers sont en scope Session, déjà, est-ce une bonne chose?

    Ensuite, si je les passe en scope Request (ce qui me permettrait d'avoir mes DAOs en scope Request aussi), comment gérer les object qui doivent etre persistant? Par exemple, sur un formulaire de création d'un objet Foobar de plusieurs pages, comment garder cette objet durant tout le processus de création?

    Je ne sais pas si je suis très clair...

  8. #8
    Membre confirmé
    Profil pro
    Inscrit en
    Mai 2008
    Messages
    394
    Détails du profil
    Informations personnelles :
    Localisation : France

    Informations forums :
    Inscription : Mai 2008
    Messages : 394
    Points : 639
    Points
    639
    Par défaut
    Bonjour,

    Tous les objets de types "service" (Controller, Service, Dao, ...) sont en générale à mettre en scope singleton. Ça te permet de construire une bonne fois pour toute au démarrage de ton serveur l'ensemble des objets "service". Ça implique que tes services soient stateless, c'est à dire qu'un service ne stock pas en variable d'instance le résultat d'une requête sql par exemple. Un service renvoie par le return le résultat de la requête.

    Pour ton DAO il devrait se faire injecter la Datasource (qui elle même est de scope singleton) et appeler datasource.getConnection() pour travailler :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    public class MonDao {
        private DataSource dataSource;
     
        public MonDao (DataSource dataSource){
            thidataSource = dataSource;
        }
     
        public MonObjet findById(Long id){
            Connection connection = dataSource.getConnection();
            // ici tu as une connexion qui peut être unique ou provenir d'un pool selon comment tu as configuré ta datasource.
            // Tu peux créer une nouvelle transaction (en général dans un DAO on se rattache plutôt à une transaction globale ouverte au niveau du service), créer un statement, l'exécuter, ...
        }
    }
    Tu ne dois pas lier ton code métier (ton Dao en l’occurrence) à la technique. Ton Dao se fiche de savoir que tu passes par JNDI pour avoir une datasource, il a juste besoin de la datasource.

    Romain.

  9. #9
    Nouveau membre du Club
    Homme Profil pro
    Inscrit en
    Mars 2006
    Messages
    87
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations forums :
    Inscription : Mars 2006
    Messages : 87
    Points : 38
    Points
    38
    Par défaut
    L'initialisation au démarrage de l'application, ce n'est pas ce que je fais avec mes DAOs annoté en @Application?

    De plus, si je fais ça, mes classes ne sont elles pas statefull puisque qu'elles existent toute la vie de l'application?


    Je suis désolé si mes questions peuvent paraitre idiote, mais je ne suis décidément pas au fait de ces choses là... Auriez-vous un tutorial à me conseiller?

    Merci beaucoup

  10. #10
    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
    Avec JSF, tu as la possibilité de référencer des objets d'un scope supérieur ou égal.
    Du coup, tu devrais utiliser 1 manager en scope request ou view qui va lui même référencer un managedBean en scope session pour les données liées à la session utilisateur et éventuellement un managedBean en scope application pour tout ce qui est transversal.
    Voici une illustration du principe
    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
     
    @ManagedBean(name = "rechercheAvanceeDataModel")
    @ViewScoped
    public class RechercheAvanceeDataModel extends AbstractLazyDataModel<Outils>
    {
        public static final long serialVersionUID = 1;
        @ManagedProperty(value = "#{scoutSessionManager}")            <--- Un objet avec des fonctions communes
        private ScoutSessionManager scoutOptions;
        @ManagedProperty(value = "#{rechercheAvanceeOptions}")      <--- Un objet qui contient les valeurs des filtres
        private RechercheAvanceeOptions rechercheOptions;
        @EJB
        private ScoutFacadeLocal facade;
     
        ...
    }

Discussions similaires

  1. Comment utiliser une datasource JNDI avec JDBC?
    Par KING_OF_GRACELAND dans le forum JDBC
    Réponses: 6
    Dernier message: 08/04/2008, 18h18
  2. comment utiliser les objets DAO
    Par marc_calagac dans le forum VBA Access
    Réponses: 3
    Dernier message: 21/06/2007, 21h01
  3. Réponses: 6
    Dernier message: 28/03/2007, 15h53
  4. Comment utiliser OUT ?
    Par Bouziane Abderraouf dans le forum CORBA
    Réponses: 3
    Dernier message: 20/07/2002, 09h35
  5. Réponses: 5
    Dernier message: 11/06/2002, 15h21

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