2017-09-14 13 views
0

Je crée une connexion à une base de données dans un projet Web en Java. Cependant, une chose que j'ai confondue;Création et fermeture de la connexion à la base de données dans ServletContextListener vs Filter

  1. Quelle est la meilleure façon de créer des connexions de base de données et de fermer la connexion? En utilisant Filter ou ServletContextListener?
  2. Une fois que j'effectue l'opération de base de données dans une servlet, comment se fermera la connexion JDBC? Ai-je besoin de fermer la connexion manuellement? Où dois-je fermer la connexion? J'ai ajouté la méthode contextDestroyed pour fermer la connexion, mais je pense que cela ne fonctionnera que lorsque le serveur Tomcat sera arrêté. Ou dois-je ouvrir et fermer la connexion dans Filter?

Voici les étapes comment je travaille

  1. Créer un DataSource dans le fichier de serveur Tomcat Context.xml en utilisant <resource> tag
  2. référence à la ressource dans le web.xml en utilisant la balise <resource-ref>
  3. Créer la connexion dans le contextInitialized du ServletContextListener
  4. Faire la base de données o pération dans le servlet de doPost ou doGet méthodes

méthode contextInitialized:

@Override 
public void contextInitialized(ServletContextEvent event) { 
    System.out.println("START CONNECTION"); 
    try { 
     Context contextEnvironment = (Context) new InitialContext().lookup("java:comp/env/"); 
     DataSource ds = (DataSource) contextEnvironment.lookup("jdbc/lunaruniversity"); 
     try { 
      Connection con = ds.getConnection(); 
      ServletContext context = event.getServletContext(); 
      context.setAttribute("dbConnection", con); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 

    } catch (NamingException e) { 
     e.printStackTrace(); 
    } 
} 

méthode de servlet doGet:

protected void doGet(HttpServletRequest request, HttpServletResponse response) 
     throws ServletException, IOException { 
    Connection con = (Connection) getServletContext().getAttribute("dbConnection"); 

    String saveStudent = request.getParameter("saveStudent"); 
    String insertSQL = "INSERT INTO STUDENT (FNAME, LNAME, EMAIL, PHONE, STATE, ZIPCODE) VALUES(?,?,?,?,?,?)"; 

     String fName = request.getParameter("fName"); 
     String lName = request.getParameter("lName"); 
     String email = request.getParameter("email"); 
     String phone = request.getParameter("phone"); 
     String state = request.getParameter("state"); 
     String zipCode = request.getParameter("zipCode"); 
     try { 
      java.sql.PreparedStatement ps = con.prepareStatement(insertSQL); 
      ps.setString(1, fName); 
      ps.setString(2, lName); 
      ps.setString(3, email); 
      ps.setString(4, phone); 
      ps.setString(5, state); 
      ps.setString(6, zipCode); 
      ps.executeUpdate(); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

méthode contextDestroyed:

@Override 
public void contextDestroyed(ServletContextEvent event) { 
    System.out.println("CLOSE CONNECTION"); 
    DataSource ds = (DataSource) event.getServletContext().getAttribute("dbConnection"); 
    try { 
     if (!ds.getConnection().isClosed()) { 
      System.out.println("CONNECTION IS CLOSED"); 
      ds.getConnection().close(); 
     } 
    } catch (SQLException e) { 
     e.printStackTrace(); 
    } 
} 

Répondre

3

1, 2 et 3: aucune de ces réponses.

Vous obtenez une connexion du DataSource lorsque vous devez démarrer une transaction. Vous passez cette connexion dans tous les appels de méthode participant à cette transaction. Ensuite, vous validez et fermez la connexion. Utilisez essayer avec-ressources pour vous assurer qu'il est toujours fermé, même en cas d'une exception:

protected void doGet(HttpServletRequest request, HttpServletResponse response) { 
    try (Connection connnection = dataSource.getConnection()) { 
     // use the connection 

     connection.commit(); 
    } 
} 
+1

Vous pouvez placer le try-with-resources dans un 'Filter' (# 3). De cette façon, vous pouvez ajouter automatiquement le code de gestion des exceptions 'rollback()' si une exception se produit, et vous pouvez également y exécuter une logique d'installation de connexion standard, par ex. 'setAutoCommit (false)'. Seul inconvénient est que la connexion est prise du pool, même pour les appels de servlet qui n'en ont pas besoin. Toujours, +1 de moi. – Andreas

+0

Avez-vous de meilleurs liens auxquels je peux me référer? Merci ! – greencheese

+0

@greencheese Liens vers quoi? Comment utiliser try-with-resources? Avez-vous essayé [Google] (https://www.google.com/search?q=try-with-resources)? – Andreas

2

Vous ne devriez jamais créer unConnection lors de l'utilisation d'une piscine. Le pool est responsable de la création effective des connexions.

Vous ne devez jamais mettre un Connection ouvert dans la mémoire globale, par ex. ServletContext. Les connexions ne doivent jamais être utilisées simultanément par plusieurs threads. Voir "Is java.sql.Connection thread safe?". Donc, pour ce que vous essayez de faire, utilisez un Filter et stockez le Connection en tant qu'attribut de requête. Mieux encore, utilisez un bloc try-with-resources dans la méthode de servlet, comme indiqué dans answer by JB Nizet, afin de ne pas prendre de connexions à partir du pool, sauf si votre servlet en a vraiment besoin.

+0

Donc, si je crée un DataSource dans la méthode contextInitialized, comment puis-je obtenir la connexion dans le filtre? Puis-je placer le DataSource dans la mémoire globale, c'est-à-dire ServletContext, puis obtenir la connexion dans le filtre? – greencheese

+1

@greencheese L'appel 'contextEnvironment.lookup()' ne crée pas * un 'DataSource'. Il récupère la 'DataSource' gérée par le pool. Et vous déplacez * tout * le code que vous avez dans 'ServletContextListener' vers le' Filter'. Autrement dit, vous supprimez le 'ServletContextListener'. – Andreas

+0

Ainsi, la conclusion de cette discussion est que ServletContextListener n'est PAS le bon endroit pour utiliser/obtenir la connexion gérée par le pool. Droite? – greencheese

2

Dans une application Web, chaque requête http d'un utilisateur s'exécute dans son propre thread (ou via un pool de threads). Avoir un objet de connexion global partagé par toutes les requêtes n'est pas une bonne idée car un seul thread à la fois sera capable de l'utiliser et cela deviendra un goulot d'étranglement pour votre application.

La configuration recommandée consiste à utiliser un pool de connexions (par exemple, C3P0) initialisé au démarrage du serveur (automatiquement via la configuration ou manuellement dans votre ServletContextListener). Le pool de connexions créera et fermera les connexions si nécessaire. Lorsque vous recevez une requête http (doPost ou doGet de la servlet), vous devez simplement obtenir une connexion du pool et la renvoyer au pool une fois que vous avez terminé le traitement de cette requête.

Vous pouvez utiliser un ServletFilter pour automatiser cette pièce. Dans votre filtre, avant l'appel à chain.doFilter(), vous obtenez une connexion du pool et le stockez dans un attribut de requête. Après l'appel à doFilter(), vous le retournez dans le pool.