I think I found it. The $Proxy97 class is a java.lang.reflect.Proxy
instance and the problem lies in the class com.ibatis.common.jdbc.logging.PreparedStatementLogProxy. When the equals
method is invoked control is being passed to this class. The
invoke method is being called and control falls down
to line 80, where the method is being invoked, passing in the statement and the
params. The passed in statement is an instance of
SybPreparedStatement but params is an instance of
$Proxy97 so of course they are not equal, and this is
why the PreparedStatement is never found within the
the latest version of iBatis.
(Compiled it from svn last week)
I'm seeing some rather odd
behavior that I can't explain. The only reason I found this is due to the fact
that I've turned on JDBC trace in the JDBC driver. On occasion I see in the
trace file SQL Exceptions occurring due to the Object already being closed. I
traced this down to the fact that the PreparedStatement was being closed twice.
As I traced this down I found the code in Spring where the exception was
actually being consumed as the exception is occurring on a call to
PreparedStatement.close(). (Of course this is negligible)
So I decided to
investigate a bit more to see why it was being called twice.
I found within the
class com.ibatis.sqlmap.engine.execution.SqlExecutor where the problem stems from. The method
on line 481
PreparedStatement prepareStatement(SessionScope session, Connection conn, String
checks to see if a
PreparedStatement already exists in the session and if not it creates the
PreparedStatement and places it into the session, so it can be found later.
(That make sense) The session simply places it into a HashMap called
preparedStatements. I can see the newly created PreparedStatement in the
session. (Object Id's match) The statement is then returned to
the executeQuery method and it's business as usual. The statement is
executed, the results are processed, everything is normal. Then in the finally
block the resultSet is closed and then the method closeStatement is executed,
passing in the session and the PreparedStatement.
Within this method, line 501, a
test is made to see if the session contains the PreparedStatement.
If the session does
not contain the statement, then the statement is closed, and this is the
behavior I'm seeing. The statement is being closed. The problem is though that
the session does contain the statement. The object Id's match up, the passed in
PreparedStatement and the object residing in the session's preparedStatements
If I execute session.hasPreparedStatementFor(String) it
returns true, it finds the entry, but if I execute session.hasPreparedStatement(ps) it
returns false. And because it returns false the PreparedStatement is being
closed. Interestingly enough, when I execute
return value is false, which simply confuses me.
Looking at the
PreparedStatement I can see that the object is of datatype $Proxy97. I believe
that this is because the PreparedStatement is being wrapped in a similar fashion
to the Connection itself. My guess at this point would be that the Proxy is not
implementing the equals() method correctly and that is why I am seeing this
behavior. (Does this sound plausible?)
So I'm guessing that I
need to figure out who is wrapping the underlying PreparedStatement. (Spring?
The Transaction Manager?)
Any insight or wisdom
into this issue will be greatly appreciated.