I personally follow the old school of thought, 1 entry, 1 exit...while this
was probably intended to describe the entry/exit points of a program itself,
I use this same idea when coding...rather then returning in the middle of a
block of code, I generally try and return at the end, while this can
sometimes increase the complexity of the code, it generally makes it easier
to read and follow...

However, I think you problem relates more to what's going on in the final
block then anywhere else...each close statement should be trapped in their
own try/catch block (as mentioned before), while this increases the amount
of code, it ensures that each statement can be called...

Shane

-----Original Message-----
From: [EMAIL PROTECTED]
[mailto:[EMAIL PROTECTED]]On Behalf Of Scott Farquhar
Sent: Wednesday, 10 April 2002 08:16 am
To: Orion-Interest
Subject: Re: JDBC try/catch Pitfall ***MUST READ***


This site demonstrates the pitfalls with using returns & finally:

http://www.cs.arizona.edu/sumatra/hallofshame/

It seems like this behaviour is not specified by the Java Language
Specification.

Cheers,
Scott

Greg Davis wrote:
> 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());
>   }
> }
>
>


--
Scott Farquhar :: [EMAIL PROTECTED]

Atlassian :: http://www.atlassian.com
      Supporting YOUR J2EE World




Reply via email to