创造&在ServletContextListener和Filter中关闭数据库连接

时间:2017-09-14 19:31:26

标签: java tomcat servlets jdbc connection-pooling

我正在使用Java在Web项目中创建数据库连接。然而,有一件事让我感到困惑;

  1. 创建数据库连接和关闭连接的最佳方法是什么?使用FilterServletContextListener
  2. 一旦我在servlet中执行数据库操作,JDBC连接将如何关闭?我是否需要手动关闭连接?我应该在哪里关闭连接?我确实添加了contextDestroyed方法来关闭连接,但我认为只有在Tomcat服务器停止时它才会起作用。
  3. 或者,我是否需要在Filter
  4. 中打开和关闭连接

    以下是我工作的步骤

    1. 使用DataSource代码
    2. 在Tomcat服务器的Context.xml文件中创建<resource>
    3. 使用web.xml代码
    4. 引用<resource-ref>中的资源
    5. contextInitialized
    6. ServletContextListener中创建连接
    7. 在servlet的doPostdoGet方法中执行数据库操作
    8. 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();
          }
      }
      

      servlet&#39; 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();
              }
          }
      

      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();
          }
      }
      

3 个答案:

答案 0 :(得分:3)

1,2和3:以上都不是。

当您需要启动事务时,您将从DataSource获得连接。您在参与该事务的所有方法调用中传递该连接。然后提交并关闭连接。使用try-with-resources确保它始终关闭,即使出现异常:

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

        connection.commit();
    }
}

答案 1 :(得分:2)

使用池时,不应该创建 Connection。该池负责实际创建连接。

你永远不应该在全局记忆中放置一个开放的Connection,例如ServletContext。连接不应该由多个线程同时使用。请参阅“Is java.sql.Connection thread safe?”。

因此,对于您要执行的操作,请使用Filter,并将Connection存储为请求属性。

更好的是,在servlet方法中使用try-with-resources块,如answer by JB Nizet所示,因此除非servlet实际需要,否则不要从池中获取连接。

答案 2 :(得分:2)

在Web应用程序中,来自用户的每个http请求都在其自己的线程中(或通过线程池)运行。拥有所有请求共享的全局连接对象并不是一个好主意,因为一次只有一个线程可以使用它,它将成为您的应用程序的瓶颈。

建议的设置是使用在服务器启动时初始化的连接池(例如C3P0)(通过config自动或在ServletContextListener中手动)。连接池将根据需要创建和关闭连接。当您收到http请求(servlet的doPost或doGet)时,您只需从池中获取连接,并在处理完该请求后将其返回池中。

您可以使用ServletFilter自动执行该部分。在过滤器中,在调用chain.doFilter()之前,您将从池中获得连接并将其存储在请求属性中。在致电doFilter()之后,您将其返回到游泳池。