Tomcat JNDI Connection Pool docs - Random Connecti

2019-07-31 06:16发布

问题:

I found this in the Tomcat documentation here

What I don't understand is why they close all the JDBC objects twice - once in the try{} block and once in the finally{} block. Why not just close them once in the finally{} clause?

This is the relevant docs:

Random Connection Closed Exceptions

These can occur when one request gets a db connection from the connection pool and closes it twice. When using a connection pool, closing the connection just returns it to the pool for reuse by another request, it doesn't close the connection. And Tomcat uses multiple threads to handle concurrent requests. Here is an example of the sequence of events which could cause this error in Tomcat:

  Request 1 running in Thread 1 gets a db connection.

  Request 1 closes the db connection.

  The JVM switches the running thread to Thread 2

  Request 2 running in Thread 2 gets a db connection
  (the same db connection just closed by Request 1).

  The JVM switches the running thread back to Thread 1

  Request 1 closes the db connection a second time in a finally block.

  The JVM switches the running thread back to Thread 2

  Request 2 Thread 2 tries to use the db connection but fails
  because Request 1 closed it.

Here is an example of properly written code to use a db connection obtained from a connection pool:

  Connection conn = null;
  Statement stmt = null;  // Or PreparedStatement if needed
  ResultSet rs = null;
  try {
    conn = ... get connection from connection pool ...
    stmt = conn.createStatement("select ...");
    rs = stmt.executeQuery();
    ... iterate through the result set ...
    rs.close();
    rs = null;
    stmt.close();
    stmt = null;
    conn.close(); // Return to connection pool
    conn = null;  // Make sure we don't close it twice
  } catch (SQLException e) {
    ... deal with errors ...
  } finally {
    // Always make sure result sets and statements are closed,
    // and the connection is returned to the pool
    if (rs != null) {
      try { rs.close(); } catch (SQLException e) { ; }
      rs = null;
    }
    if (stmt != null) {
      try { stmt.close(); } catch (SQLException e) { ; }
      stmt = null;
    }
    if (conn != null) {
      try { conn.close(); } catch (SQLException e) { ; }
      conn = null;
    }
  }

回答1:

I normally just close my connection once in the finally block and I haven't found any issues.

However, double close may be needed in more complicated use cases. For example, if you open multiple statements or multiple connections in the try block, you want close each one right after you use it. Then, you need to catch any left-over due to exceptions in the finally block. For example,

try {
    conn = ds1.getConnection();
    ... Do something with datasource 1 ...
    conn.close();
    conn=null;

    conn = ds2.getConnection();
    ... Do something with datasource 2 ...
    conn.close();
    conn = null;
  } catch (SQLException e) {
    ... deal with errors ...
  } finally {
    if (conn != null) {
      try { conn.close(); } catch (SQLException e) { ; }
      conn = null;
    }
  }


回答2:

Or you can using Spring-JDBC and forget about all this complications (Spring-JDBC will deal with this automatically for you)