Reputation: 53
I have a server application that uses the Tomcat JDBC connection pool.
This is the code I use to create the DataSource:
PoolProperties connProperties = new PoolProperties();
connProperties.setUrl(resources.getProperty("db.url"));
connProperties.setDriverClassName(resources.getProperty("db.driver"));
connProperties.setUsername(resources.getProperty("db.user"));
connProperties.setPassword(resources.getProperty("db.password"));
connProperties.setJmxEnabled(true);
connProperties.setTestWhileIdle(false);
connProperties.setValidationQuery("SELECT 1");
connProperties.setTestOnReturn(false);
connProperties.setValidationInterval(30000);
connProperties.setTimeBetweenEvictionRunsMillis(30000);
connProperties.setMaxActive(500);
connProperties.setInitialSize(50);
connProperties.setMaxWait(10000);
connProperties.setRemoveAbandonedTimeout(60);
connProperties.setMinEvictableIdleTimeMillis(60000);
connProperties.setSuspectTimeout(60);
connProperties.setMaxIdle(50);
connProperties.setMinIdle(10);
connProperties.setLogAbandoned(false);
connProperties.setRemoveAbandoned(true);
connProperties.setJdbcInterceptors("org.apache.tomcat.jdbc.pool.interceptor.ConnectionState;"+
"org.apache.tomcat.jdbc.pool.interceptor.StatementFinalizer");
dataSource = new DataSource();
dataSource.setPoolProperties(connProperties);
Then I have a method to get a connection from the pool
protected Connection getDbConnection() throws Exception
{
dbConn = dataSource.getConnection();
return dbConn;
}
And every time I want to execute a statement I call this code:
protected CallableStatement executeCSqlQuery(String sql) throws Exception
{
CallableStatement cstmt;
ResultSet rs = null;
try {
cstmt = getDbConnection().prepareCall(sql);
cstmt.execute();
} catch (SQLException e) {
throw e;
}
return cstmt;
}
And this is an example of a call to the previous code:
try {
cstmt = dbConnection.executeCSqlQuery(query);
rs = cstmt.getResultSet();
} catch (Exception e) {
// do smething
} finally {
try {
if (cstmt != null) {
cstmt.close();
}
dbConnection.shutdown();
} catch (Exception e) {
// do something
}
}
public void shutdown() {
if (this.dbConn != null)
this.dbConn.close();
}
The problem I'm facing is that every now and then, I'm getting an exception "Statement is closed" when I execute a call in a Thread every X seconds. I'm not sure why this happens. I'm thinking that it could be a driver bug or something failing with the connection to the database (that runs in a different server).
I'm out of ideas. What am I missing?
Should I use c3p0 connection pool instead?
Upvotes: 2
Views: 5239
Reputation: 170
I created the bounty to help out Reznik but I ended up figuring out what the problem was by looking at his code.
The problem is that every time a new connection is fetched from the pool in
protected Connection getDbConnection() throws Exception
{
dbConn = dataSource.getConnection();
return dbConn;
}
the object dbConn
is updated to a new connection.
Example:
T1
invokes getDbConnection()
T2
invokes getDbConnection()
T1
executes the query, processes the resultSet
and calls shutdown()
public void shutdown() {
if (this.dbConn != null)
this.dbConn.close();
}
Because T2
updated the object, the connection being used by T2
will be shutdown by T1
T2
tries to use the connection but it is already closed.
This way, instead of always updating the connection, just return it and then add the extra logic to close the connection that was fetched from the pool.
Upvotes: 4
Reputation: 201399
I notice two things:
1) connProperties.setTestOnReturn(false);
which should be changed to true. Otherwise your connection isn't necessarily valid. And you might not get notified until you receive an invalid Statement.
2) You should ALWAYS close your ResultSet, Statement and Connection objects. It does involve a lot of boilerplate, or you could use my static Close utility method.
Upvotes: 2
Reputation: 15498
1) protected CallableStatement executeCSqlQuery(String sql) throws Exception
returns the callable statement. If you are trying to use it again after closing it inside the method, you'll probably get that error. All the processing involving that object should be done before closing it.
2) The same method has a catch(SQLException ){throw e}
. You'd either want to handle the exception there, or if you want to propagate it remove the try-catch
3) I can see in the last piece of code rs = cstmt.getResultSet();
It is always a good practice to close the resources in the inverse order that they were obtained, as you've read in the post you linked for Peter. So rs.close(); cstmt.close(); connection.close();
. It's not included in your sample, but if you're returning the ResultSet after closing it, you'll have the same problem described at 1)
Upvotes: 1