Hi Stefan I would try this one:
Connection conn = null; Statement stmt = null; // Or PreparedStatement if needed try { conn = ... get connection from connection pool ... stmt = conn.createStatement("select ..."); ResultSet rs = stmt.executeQuery(); ... iterate through the result set ... } 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 (stmt != null) { try { stmt.close(); } catch (SQLException e) { ; } } if (conn != null) { try { conn.close(); } catch (SQLException e) { ; } } } We don´t need to null conn and stmt variables because the sanity check on finally block. The resultset will only exist if and only if you already have a statement, and "A ResultSet object is automatically closed when the Statement object that generated it is closed, re-executed, or used to retrieve the next result from a sequence of multiple results. ", thats why it is in a more restrictive scope w/out close() http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html On the race condition: javadoc on Connection.close() states "Calling the method close on a Connection object that is already closed is a no-op. ", see: http://java.sun.com/javase/6/docs/api/java/sql/Connection.html#close() This race condition should be threated as connection pool´s bug, IMHO. Flavio Crispim PS: English isn´t my mother language... Alan Chaney <a...@compulsivecreative.com> gravou em 19/01/2009 21:24:43: > Hi Stefan > > I went and read the comments more carefully and it seems to me that the > proposed solution is an attempt to avoid a race condition between > issuing the 'close' in > one thread and then it being closed again whilst its being used in > another thread. > > If the problem is closing it twice then I can't see why its not just > closed in the 'finally' block, once for each thread. > > If it is a concurrency problem then I suspect that the proposed solution > in the docs isn't the right one anyway. I'd suspect that the problem is > more to do with threads not seeing each others memory state properly. > Isn't this is a case of a variable (in this case 'conn') actually being > a reference to an object which is shared between threads? > Because of the JVM memory model it is possible for two threads not to be > properly synchronized - see Doug Lea et.al and 'happens before' . > Personally, I feel that the correct solution is to synchronize access > to the connection object when it is retrieved and closed. > > I have to go out now and I don't have any more time to consider this > today, but I'd be interested to hear other people's comments on this topic. > > Regards > > Alan Chaney > > > Stefan Riegel wrote: > > Thanks Alan, just to make the thing really clear. You propose code > > like this: > > > > public void execute() { > > Connection conn = null; > > Statement stmt = null; > > ResultSet rs = null; > > Context envContext = null; > > try { > > Context initContext = new InitialContext(); > > envContext = (Context) initContext.lookup("java:/comp/env"); > > DataSource ds = (DataSource) envContext.lookup("jdbc/swex"); > > conn = ds.getConnection(); > > stmt = conn.createStatement(); > > rs = stmt.executeQuery("some sql"); > > // iterate through the result set ... > > } catch (SQLException e) { > > e.printStackTrace(); > > } catch (NamingException e) { > > e.printStackTrace(); > > } finally { > > if (rs != null) { > > try { > > rs.close(); > > } catch (SQLException e) { > > e.printStackTrace(); > > } > > } > > if (stmt != null) { > > try { > > stmt.close(); > > } catch (SQLException e) { > > e.printStackTrace(); > > } > > } > > if (conn != null) { > > try { > > conn.close(); > > } catch (SQLException e) { > > e.printStackTrace(); > > } > > } > > if (envContext != null) { > > try { > > envContext.close(); > > } catch (NamingException e) { > > e.printStackTrace(); > > } > > } > > } > > > > > > For me this looks fine but I'm still confused, why they complicated > > things in the example of "properly written code" > > http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html? > > > > > Hmm... frankly the code in the docs you refer to above seems odd to > me... why repeat in the 'finally' something you've done in the 'try'? > > I can see that setting the variables to null would ensure that all > references were released and the objects were made candidates for garbage > collection but that could be done in the finally block anyway at some > convenient point. > > Obviously in your code you might not want to obtain and release the > context for every JDBC operation - that would probably be done in some > kind of start-up/shutdown code for your app, and of course your > exception handling may need some more work depending upon the way you > want to present the error > to your users, but I assumed that the issue you are concerned with is > preventing resource leaks. > > Any comments anyone else? > > Regards > > Alan > > > > > Do I miss some important point here? > > > > Stefan > > > > > > Alan Chaney schrieb: > >> Hi Stefan > >> > >> You don't need to repeat the stmt.close();conn.close() etc in the > >> 'try' body. The 'finally' by definition is ALWAYS called and that is > >> where you should do the tidy up... > >> > >> Alan Chaney > >> > >> > >> > >> Stefan Riegel wrote: > >>> I guess I understood the point with the "Random Connection Closed > >>> Exceptions" Problem. > >>> > >>> See at the end of > >>> http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource- > examples-howto.html > >>> > >>> > >>> As I understand, only the connection itself must be protected this > >>> way. The statement and ResultSet must not. Is the following, > >>> simplified code also correct? > >>> > >>> Connection conn = null; > >>> Statement stmt = null; > >>> ResultSet rs = null; > >>> try { > >>> conn = ... get connection from connection pool ... > >>> stmt = conn.createStatement("select ..."); > >>> rs = stmt.executeQuery(); > >>> ... iterate through the result set ... > >> > >> // SUPERFLUsOUS > >>> rs.close(); > >>> stmt.close(); > >>> conn.close(); // Return to connection pool > >>> conn = null; // Make sure we don't close it twice > >> //SUPERFLUOUS > >> > >> > >>> } catch (SQLException e) { > >>> ... deal with errors ... > >>> } finally { > >>> try { > >>> rs.close(); > >>> } catch (SQLException e) { > >>> // deal with errors > >>> } > >>> try { > >>> stmt.close(); > >>> } catch (SQLException e) { > >>> // deal with errors > >>> } > >>> if (conn != null) { > >>> try { > >>> conn.close(); > >>> } catch (SQLException e) { > >>> // deal with errors > >>> } > >>> conn = null; > >>> } > >>> } > >>> > >>> Thanks. > >>> > >> > >> --------------------------------------------------------------------- > >> To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > >> For additional commands, e-mail: users-h...@tomcat.apache.org > > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org > For additional commands, e-mail: users-h...@tomcat.apache.org > --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org