- Retry -

I don't know if there are any issues with finally clauses - at least you
should not wrap all close() in your finally block within _one_ try/catch
clause. Use e.g. a static helper class which encloses every close() in a
separate try/catch block. I have never had any issues by doing so -
especially in case of buggy oracle jdbc drivers.

Jens

| -----Original Message-----
| From: [EMAIL PROTECTED]
| [mailto:[EMAIL PROTECTED]]On Behalf Of Greg Davis
| Sent: Tuesday, April 09, 2002 4:56 PM
| To: Orion-Interest
| Subject: JDBC try/catch Pitfall ***MUST READ***
|
|
| This deals with try/catch blocks and finallys. I always believed that "no
| matter what" a finally block is always called.  While this seems to remain
| true, it does not seem to necessarily properly call the code within the
| block.  In the section below I have some code and explanation of how a
| finally gets called, but does not execute the code within.
|
| There seems to be an issue with closing a JDBC connection if a method
| returns in the middle of the try/catch block.  It seems to call
| the finally,
| but does not close the connection.  It does seem to call static
| methods like
| System.out.println() perfectly fine.  I don't know if it being static has
| anything to do with it.  I haven't researched it too far since it
| was really
| hard to find.  First off you have to have a Factory like a ConnectionPool
| that spawns out inscances of an object for other classes to use. Then it
| must need to have the user close it's connection at some point so the
| Factory can control resources. The only example I really have on hand is a
| JDBC connection pool in a J2EE app server.  This is where the
| problem occurd
| for us.  If the methods "returns" are moved outside the try/catch
| block, the
| Connection.close() happens properly and the ConnectionPool does not
| complain.
|
| I realize the getColumnClose() is the better way to implement the code
| ayway, but I wanted to show everyone this problem in case they
| accidentally
| do it in their code somewhere.  Any returns in the try or catches
| seemed to
| make the finally not be properly executed. I seem to remember some wierd
| rule about this at JavaOne last year, but my head is still racing from all
| that information. :-)
|
| Any comments?
|
| package test;
|
| import java.sql.*;
| import javax.sql.DataSource;
| import javax.naming.*;
|
| /**
|  * <p>Title: TryCatchTest</p>
|  * <p>Description: This is a test application for try/catch problem.  If
| using
|  * a Connection Pool in JDBC and you try to "return" a value within a
| try/catch
|  * that is inside a method, the finally of that try/catch is not
| completely
| run.
|  * It seems to go through the finally(I.E. Sytem.out.println() works, but
| the
|  * Connection.close() is either never called or not executed.  If the
| "return"
|  * is moved to the outside of the catch block, the connection is properly
| closed.
|  * <br>
|  * We found this because a J2EE server which had a connection pool was
| telling
|  * us we were not closing our connections.  I dn't know if there is some
| rule that
|  * when a "return" has been called only static methods or something like
| that can
|  * be called.</p>
|  * <p>Copyright: Copyright (c) 2002</p>
|  * <p>Company: Western Electronics </p>
|  * @author <a href="mail:[EMAIL PROTECTED]">Greg Davis</a>
|  * @version 1.0
|  */
|
| public class TryCatchTest
| {
|   Context jndiContext;
|
|   public TryCatchTest()
|   {
|     try
|     {
|       jndiContext = new InitialContext();
|     }
|     catch(NamingException ne)
|     {}
|   }
|
|   public String getColumnNoClose()
|   {
|     Connection conn = null;
|     PreparedStatement ps = null;
|     ResultSet rs = null;
|     try
|     {
|       String sql ="SELECT table_name FROM sequence";
|       conn
| =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
|       ps = conn.prepareStatement(sql);
|       rs = ps.executeQuery();
|       if(rs != null && rs.next())
|       {
|         //This return causes the ?non-static? code within the
| finally to not
| to be run.
|         return rs.getString("table_name");
|       }
|       //same here, the finally ?non-static? code is not called.
|       return null;
|     }
|     catch(NamingException ne)
|     {
|       //same here, the finally ?non-static? code is not called.
|       return null;
|     }
|     catch(SQLException sqle)
|     {
|       sqle.printStackTrace();
|       //The same problem occurs here.  The finally ?non-static?
| code is not
| called
|       return null;
|     }
|     finally
|     {
|       //This system out works, but the conn.close() does not.
| The only way
| I
|       //know how to check this is to create a ConnectionPool yourself that
| watches
|       //the connections it spawns out, or user a pre-built one
| that does the
| same.
|       //We use Orion 1.5.4 J2EE App server (free for development). if you
| want
|       //to test this out.
|       System.out.println("Finally called in noClose()");
|       try
|       {
|         if(rs != null)
|           rs.close();
|         if(ps != null)
|           ps.close();
|         if(conn != null)
|           conn.close();
|       }
|       catch(SQLException sqle)
|       {
|         sqle.printStackTrace();
|       }
|     }
|   }
|
|   public String getColumnClose()
|   {
|     String returnValue = null;
|     Connection conn = null;
|     PreparedStatement ps = null;
|     ResultSet rs = null;
|     try
|     {
|       String sql ="SELECT table_name FROM sequence";
|       conn
| =((DataSource)jndiContext.lookup("jdbc/mySourceDS")).getConnection();
|       ps = conn.prepareStatement(sql);
|       rs = ps.executeQuery();
|       if(rs != null && rs.next())
|       {
|         //This does call the finally
|         returnValue = rs.getString("table_name");
|       }
|
|     }
|     catch(NamingException ne)
|     {}
|     catch(SQLException sqle)
|     {
|       //This allso calles the finally if I break the quey
|       sqle.printStackTrace();
|     }
|     finally
|     {
|       //This one works normally
|       System.out.println("Finally called in Close()");
|       try
|       {
|         if(rs != null)
|           rs.close();
|         if(ps != null)
|           ps.close();
|         if(conn != null)
|           conn.close();
|       }
|       catch(SQLException sqle)
|       {
|         sqle.printStackTrace();
|       }
|     }
|     return returnValue;
|   }
|
|   public static void main(String[] args)
|   {
|     TryCatchTest tct1 = new TryCatchTest();
|     System.out.println("tct1.getColumnNoClose():" +
| tct1.getColumnNoClose());
|     System.out.println("tct1.getColumnClose():" +tct1.getColumnClose());
|   }
| }


Reply via email to