Hello Alan,

unfortunately I'm not very experienced in "thread programming". But as I understand does the proposed solution in the docs avoid the problem of closing the connection object of the second thread. Yes, I find the solution somewhat ugly and not very intuitive.

But the code below should also work. So it looks easier for me. This sequence...

- 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.

... cannot happen any more, because the connection gets closed exactly once (only if it is opened before).

So I'm still confused about the docs. They exist for a long time and I cannot believe, that no one before me wondered about it. So I guess I'm missing something. But what?

Alan Chaney schrieb:
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

Reply via email to