--- PreparedStatement.java Sat Feb 17 01:45:00 2001 +++ PreparedStatement.java.new Wed Jun 20 12:34:57 2001 @@ -39,10 +39,12 @@ // Some performance caches private StringBuffer sbuf = new StringBuffer(); - // We use ThreadLocal for SimpleDateFormat's because they are not that - // thread safe, so each calling thread has its own object. - private ThreadLocal tl_df = new ThreadLocal(); // setDate() SimpleDateFormat - private ThreadLocal tl_tsdf = new ThreadLocal(); // setTimestamp() SimpleDateFormat + // Because SimpleDateFormat is not thread safe we create one for each + // PreparedStatemnt here AND synchronize on it for each usage. + // We can NOT use ThreadLocal because they are not freed until the thread + // completes. This would be a memory leak for long running threads. + private SimpleDateFormat df = null; + private SimpleDateFormat tsdf = null; /** * Constructor for the PreparedStatement class. @@ -90,9 +92,6 @@ * New in 7.1 - overides Statement.close() to dispose of a few local objects */ public void close() throws SQLException { - // free the ThreadLocal caches - tl_df.set(null); - super.close(); } @@ -332,14 +331,18 @@ */ public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { - SimpleDateFormat df = (SimpleDateFormat) tl_df.get(); - if(df==null) { + // The df DateFormat is initialized here to delay creation until needed. + if( df == null ) { + synchronized( this ) { + if( df == null ) { df = new SimpleDateFormat("''yyyy-MM-dd''"); - tl_df.set(df); + } + } } - set(parameterIndex, df.format(x)); - + // We must synchronize here because SimpleDateFormat is not thread safe. + synchronized( df ) { + set( parameterIndex, df.format(x) ); // The above is how the date should be handled. // // However, in JDK's prior to 1.1.6 (confirmed with the @@ -351,6 +354,7 @@ // //set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000))); } + } /** * Set a parameter to a java.sql.Time value. The driver converts @@ -375,17 +379,22 @@ */ public void setTimestamp(int parameterIndex, Timestamp x) throws SQLException { - SimpleDateFormat df = (SimpleDateFormat) tl_tsdf.get(); - if(df==null) { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); - tl_tsdf.set(df); + // The tsdf DateFormat is initialized here to delay creation until needed. + if( tsdf == null ) { + synchronized( this ) { + if( tsdf == null ) { + tsdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + tsdf.setTimeZone(TimeZone.getTimeZone("GMT")); + } + } } - df.setTimeZone(TimeZone.getTimeZone("GMT")); + // We must synchronize here because SimpleDateFormat is not thread safe. + synchronized( tsdf ) { // Use the shared StringBuffer synchronized(sbuf) { sbuf.setLength(0); - sbuf.append("'").append(df.format(x)).append('.').append(x.getNanos()/10000000).append("+00'"); + sbuf.append("'").append(tsdf.format(x)).append('.').append(x.getNanos()/10000000).append("+00'"); set(parameterIndex, sbuf.toString()); } @@ -393,6 +402,7 @@ // to be identical. Pays to read the docs ;-) //set(parameterIndex,"'"+x.toString()+"'"); } + } /** * When a very large ASCII value is input to a LONGVARCHAR parameter,