Reputation: 1256
I'm using Axis2 with Apache Tomcat. I need the clients of the web service to be able to query a database, so I found on the internet that, by adding the following resource to the Tomcat's context, it will automatically create a connection pool:
Resource name="jdbc/TestDB" auth="Container" type="javax.sql.DataSource" removeAbandoned="true" removeAbandonedTimeout="30" maxActive="80" maxIdle="30" maxWait="10000" username="user" password="" driverClassName="org.postgresql.Driver" url = "jdbc:postgresql://localhost:5432/mydb" useUnicode="true" characterEncoding="utf-8" characterSetResults="utf8" validationQuery="/* ping */ SELECT 1"
It seems to be working, but now what I want to do is reuse the same PreparedStatement, so it won't be parsed every time a client makes a request. So, I made the PreparedStatement static for all client connections and when I create it, i invoke statement.setPoolable(true), which, from what I understand, is redundant (a PreparedStatement is already poolable). I hoped that this way, the PreparedStatement won't be tied to a single connection. Still, I get the error:
java.sql.SQLException: org.apache.tomcat.dbcp.dbcp.DelegatingPreparedStatement with address * is closed.
The weird thing is, if i call statement.isClosed() before i make any set, it returns false. Then, I set something and it throws that exception.
The code is:
try {
Connection conn;
Context envCtx = (Context) new InitialContext().lookup("java:comp/env");
DataSource ds = (DataSource) envCtx.lookup("jdbc/TestDB");
conn = ds.getConnection();
if(statement == null){
//statement is static, so it won't be null at the second call
statement = conn.prepareStatement(query);
statement.setPoolable(true);
}
if(statement.isClosed()){
statement = conn.prepareStatement(query);
//it never gets here
}
else{
Logger.getLogger(HelloAxisWorld.class.getName()).log(Level.INFO, "STATEMENT IS NOT CLOSED", new Object());
//it always gets here
}
statement.setString(1, par1); //here, the second call throws an exception
ResultSet rs = statement.executeQuery();
while (rs.next()) {
cur_value = rs.getInt("cur_value");
}
rs.close();
conn.close();
}catch (Exception ex) {
Logger.getLogger(HelloAxisWorld.class.getName()).log(Level.SEVERE, null, ex);
}
I don't understand why does statement.isClosed return false, but then the exception says it is closed. Maybe this is not the way to reuse a preparedStatement, but then how can i do it? I read that, if I call conn.prepareStatement on the same query, jdbc will return the PreparedStatement from cache (it will not be parsed again), but I'm not sure if it's true.
Upvotes: 0
Views: 416
Reputation: 1592
There is a project called c3p0 which was made specifically to handle one of the cases you are having. The website is here https://sourceforge.net/projects/c3p0/ and here http://www.mchange.com/projects/c3p0/ It handles data-source JNDI binding, connection pooling and statement pooling. There also is a reference on stackoverflow on someone using this library with servlets what-is-a-good-strategy-for-caching-prepared-statements-in-tomcat
Upvotes: 0