After getting fed up with c3p0's constant locking I'm turning to BoneCP for an alternative connection pool for my database. I have a server app that processes around 7,000 items per minute and needs to log those items into our MySQL database. I currently have 100 worker threads and have set up my pool like such:
BoneCPConfig config = new BoneCPConfig();
config.setJdbcUrl("jdbc:mysql://"+Settings.MYSQL_HOSTNAME+"/"+Settings.MYSQL_DATABASE+"?autoReconnectForPools=true" );
config.setUsername(Settings.MYSQL_USERNAME);
config.setPassword(Settings.MYSQL_PASSWORD);
config.setMinConnectionsPerPartition(5);
config.setMaxConnectionsPerPartition(10);
config.setPartitionCount(5);
config.setAcquireIncrement(5);
connectionPool = new BoneCP(config); // setup the connection pool
Are those acceptable settings for such an app? I'm asking because after a minute or two into running I was getting BoneCP exceptions when trying to call getConnection on the pool. Thanks for the help.
Here is the code I was using for the db calls in my worker threads, it can't fail on the dbConn = this.dbPool.getConnection() line. Am I not closing connections properly?
private void insertIntoDb() {
try {
Connection dbConn = this.dbPool.getConnection();
try {
PreparedStatement ps3 = dbConn.prepareStatement("INSERT IGNORE INTO test_table1 SET test1=?, test2=?, test3=?");
ps3.setString(1, "some string");
ps3.setString(2, "some other string");
ps3.setString(3, "more strings");
ps3.execute();
ps3.close();
PreparedStatement ps4 = dbConn.prepareStatement("INSERT IGNORE INTO test_table2 SET test1=?, test2=?, test3=?");
ps4.setString(1, "some string");
ps4.setString(2, "some other string");
ps4.setString(3, "more strings");
ps4.execute();
ps4.close();
} catch(SQLException e) {
logger.error(e.getMessage());
} finally {
try {
dbConn.close();
} catch (SQLException e) {
logger.error(e.getMessage());
}
}
} catch(SQLException e) {
logger.error(e.getMessage());
}
}
This is the error I was seeing:
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
[java] WARN [com.google.common.base.internal.Finalizer] (ConnectionPartition.java:141) - BoneCP detected an unclosed connection and will now attempt to close it for you. You should be closing this connection in your application - enable connectionWatch for additional debugging assistance.
ERROR pool-2-thread-39 2010-09-04 13:36:19,798 com.test.testpackage.MyTask - null
java.sql.SQLException
at com.jolbox.bonecp.BoneCP.getConnection(BoneCP.java:381)
Are those acceptable settings for such an app? I'm asking because after a minute or two into running I was getting boneCP exceptions when trying to call getConnection on the pool. thanks for the help.
If you have 100 workers, why do you limit the pool to 50 connections (number of partitions x max number of connections per partition i.e. 5 x 10 in your case)?
Am I not closing connections properly?
Looks ok (but maybe enable connectionWatch as hinted to see what the warning is about exactly). Personally, I close all the resources I use, including statement and result sets. Just in case, here is the idiom I use:
Connection conn = null;
PreparedStatement pstmt = null;
ResultSet rs = null;
try {
conn = pool.getConnection();
pstmt = conn.prepareStatement(SOME_SQL);
pstmt.setFoo(1, foo);
...
rs = pstmt.executeQuery();
...
} finally {
if (rs != null) try { rs.close(); } catch (SQLException quiet) {}
if (pstmt != null) try { pstmt.close(); } catch (SQLException quiet) {}
if (conn != null) try { conn.close(); } catch (SQLException quiet) {}
}
You could group the above calls in a static method of a utility class.
Or you could use DbUnit.closeQuietly(Connection, Statement, ResultSet) from Commons DbUtils that already does this.
Related
I've got a spring application, one of it's functions is to be able to take any piece of SQL and run it, a poller polls a folder for a trigger file containing the location of a SQL file, the application then reads the SQL file and places contents into the 'sqlquery' message header.
Problem we seem to have is that exceptions aren't being thrown when the SQL fails.
try
{
if ((msg.getHeaders().containsKey("sqlQuery"))&&(!"".equals(msg.getHeaders().get("sqlQuery"))))
{
_log.debug("Executing: " + msg.getHeaders().get("sqlQuery"), UID);
jdbcTemplate.execute((String) msg.getHeaders().get("sqlQuery"));
_log.info("Query executed successfully.", UID);
}
result = "S";
} catch (Exception ex) {
ex.printStackTrace();
_log.error(ex, ex, UID);
}
JDBC Drivers is Microsoft JDBC Driver 4.2, connecting to a SQL Server 2014 database.
I've tried running this with a simple 'Select 1/0' which would obviously throw a divide by zero error, but we get a successful response.
2018-07-19 16:36:01,738|org.springframework.jdbc.datasource.DataSourceUtils|sqlFileChannelTaskExecutor-6|DEBUG|Returning JDBC Connection to DataSource
2018-07-19 16:36:01,738|org.springframework.integration.transformer.MessageTransformingHandler|sqlFileChannelTaskExecutor-6|DEBUG|org.springframework.integration.transformer.MessageTransformingHandler#c6d1b7 received message: GenericMessage [payload={UPDATED=1}, headers={UID=MCTest, errorChannel=logSqlErrorChannel, id=318f54b8-2889-22af-1009-e191550c75eb, sqlQuery=Select 1/0, timestamp=1532014561738}]
2018-07-19 16:36:01,738|org.springframework.beans.factory.support.DefaultListableBeanFactory|sqlFileChannelTaskExecutor-6|DEBUG|Returning cached instance of singleton bean 'integrationEvaluationContext'
2018-07-19 16:36:01,738|org.springframework.beans.factory.support.DefaultListableBeanFactory|sqlFileChannelTaskExecutor-6|DEBUG|Returning cached instance of singleton bean 'integrationConversionService'
2018-07-19 16:36:01,738|MCTest|sqlFileChannelTaskExecutor-6|DEBUG|SQL Step Started
2018-07-19 16:37:16,926|MCTest|sqlFileChannelTaskExecutor-6|DEBUG|Executing: Select 1/0
2018-07-19 16:37:22,530|org.springframework.jdbc.core.JdbcTemplate|sqlFileChannelTaskExecutor-6|DEBUG|Executing SQL statement [Select 1/0]
2018-07-19 16:37:28,278|org.springframework.jdbc.datasource.DataSourceUtils|sqlFileChannelTaskExecutor-6|DEBUG|Fetching JDBC Connection from DataSource
2018-07-19 16:37:28,278|org.springframework.jdbc.datasource.DriverManagerDataSource|sqlFileChannelTaskExecutor-6|DEBUG|Creating new JDBC DriverManager Connection to [jdbc:sqlserver://<Server>;databaseName=<Database]
2018-07-19 16:37:33,069|org.springframework.jdbc.datasource.DataSourceUtils|sqlFileChannelTaskExecutor-6|DEBUG|Returning JDBC Connection to DataSource
2018-07-19 16:37:33,069|MCTest|sqlFileChannelTaskExecutor-6|INFO |Query executed successfully.
Can anyone help explain why exceptions aren't getting captured/thrown?
share you query.. and use catch (ArithmeticException ae) where as if you have issues in understanding the 1/0 ArithmeticException.
hope it will work.
I have a small Java application for testing purposes. I have moved to hikari recently. What I notice is that I keep getting this error.
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
java.sql.SQLTransientConnectionException: HikariPool-1 - Connection is not available, request timed out after 30000ms.
at com.zaxxer.hikari.pool.HikariPool.createTimeoutException(HikariPool.java:602)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:195)
at com.zaxxer.hikari.pool.HikariPool.getConnection(HikariPool.java:145)
at com.zaxxer.hikari.HikariDataSource.getConnection(HikariDataSource.java:85)
Below is my settings for the hikari initially.
HikariConfig config = new HikariConfig();
config.setJdbcUrl("jdbc:mysql://localhost:3306/****");
config.setUsername("***");
config.setPassword("*****");
config.setMaximumPoolSize(20);
Hardly its being used my two devices and I ensure towards the end I do close it. So I don't know why it keep getting the error? What could be the issue or is there some settings which I need to change?
My hikari version is HikariCP-2.6.1.jar.
Your database is not obtaining connection within (30000 milliseconds that is default connectionTimeout property) because of network latency or some of the queries which are taking too long to execute(more than 30000 milliseconds).
Please try to increase value of property connectionTimeout.
YML configuration example:
spring:
datasource:
hikari:
minimumIdle: 2
maximumPoolSize: 10
idleTimeout: 120000
connectionTimeout: 300000
leakDetectionThreshold: 300000
Java Config example:
HikariConfig config = new HikariConfig();
config.setMaximumPoolSize(20);
config.setConnectionTimeout(300000);
config.setConnectionTimeout(120000);
config.setLeakDetectionThreshold(300000);
I am using spring boot and I was facing the same problem, and my solution was to get the connection like this "DataSourceUtils.getConnection(dataSource)". So I change from dataSource.getConnection() to DataSourceUtils.getConnection(dataSource).
In my case the code wasn't closing the connections.
Try-with-resources fixed it:
try (
Connection connection = dataSource.getConnection();
Statement statement = …
) {
…
}
In my case I was using JPA and hence using EntityManagerFactory for persistence and query for my springBoot project and got the same error.
The reason was in any CRUD operation I was not closing EntityManager once the operation is done hence exhausting the resources.
Hope this helps!!
EntityManager em = emf.createEntityManager();
Customer c = em.find(Customer.class , id);
em.close();
request timeout is not something that you can fix by increasing the timeout. Perhaps you'd need to evaluate all the queries from your service and implement indexing if it's needed
This can also happen if the client app is requesting lot of open connections and the database server setting has a max limit on number of pool connections. So the client app is unable to get any more connections from the database server. Check the database server connections pool to see if the max is exceeded during the time period of the errors.
Took forever to figure it out... In my case I used solution similar to #Andres Rincon:
try (Connection connection = DataSourceUtils.getConnection(jdbcTemplate.getDataSource())) {
// some code here
}
What fixed the issue in my case was to add proper indexing in the proper db tables. Take a look at the queries / transactions you're making to the db.
In my case the statement that was causing the latency was an UPDATE statement, e.g.
UPDATE table_name WHERE column1 = value1, column2 = value2;
What fixed the issue for me in this case was to add an index in that table for those two columns like:
CREATE INDEX index_name ON table_name (column1, column2);
Another good reason could be that you're not closing out your connections. You can close the connections with a try-with-resource statement like:
try( Connection connection = datasource.getConnection() ){
//your code
}
In my opinion, increasing the timeout as Girdhar Singh Rathore suggested is not ideal. It could temporarily fix the issue, but at some point you'll need to take care of proper indexing and closing connections management.
Hope this helps.
Generally opened and unclosed connections cause this problem.There is a limit of application servers to connect database and if you over this limit it will be crash your environment.
Connection must be stand on singleton pattern but if you really need to open a datasource or connect external datasource like reports you must close your connection in your finally block where you open connection block
connection.getConnection().rollback();
connection.getConnection().close();
You must also close if you are using PersistenceJpa without singleton
persistenceJPAConfig.dataSource().getConnection().rollback();
persistenceJPAConfig.dataSource().getConnection().close();
If you are using some stress test tools via creating threads to test your methods you probably get this error on your queries which take long time.It will be lead the way optimizing your queries or service instance size.
In my case a:
o.h.engine.jdbc.spi.SqlExceptionHelper: HikariPool-1 - Connection is not available, request timed out after 30019ms.
i.s.commons.web.error.ExceptionLogger: Internal Server Error
org.springframework.transaction.CannotCreateTransactionException: Could not open JPA EntityManager for transaction; nested exception is org.hibernate.exception.JDBCConnectionException: Unable to acquire JDBC Connection
Was caused by a too low spring.hikari.maximumPoolSize in the application properties, increasing from 5 to 20 solved the issue.
The log message is kind of miss-leading.
In my case I used solution similar to #Andres Rincon:
try (Connection conn = connectionManager.getDataConnection()) {
Statement stmt = conn.createStatement();
...
conn.close();
} catch (Exception e) {
e.printStackTrace();
}
I've fixed my issue using:
increase the minIdle and maxPool
spring.datasource.hikari.minimumIdle=20
spring.datasource.hikari.maximumPoolSize=30
spring.datasource.hikari.connectionTimeout=50000
To debug the issue/check if the values are ok, enable the logging for Hikari:
logging.level.com.zaxxer.hikari.HikariConfig=DEBUG
logging.level.com.zaxxer.hikari=TRACE
The logs will look like:
DEBUG 2023-01-06T16:12:31.932018849Z HikariPool-1 - Before cleanup stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:31.932665522Z HikariPool-1 - After cleanup stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:31.932733949Z HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:32.495269726Z HikariPool-1 - After adding stats (total=17, active=0, idle=17, waiting=0)
DEBUG 2023-01-06T16:12:38.309953158Z HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:39.200246897Z HikariPool-1 - Fill pool skipped, pool is at sufficient level.
DEBUG 2023-01-06T16:12:44.812065268Z HikariPool-1 - Before cleanup stats (total=18, active=0, idle=18, waiting=0)
DEBUG 2023-01-06T16:12:44.812822113Z HikariPool-1 - After cleanup stats (total=18, active=0, idle=18, waiting=0)
Good Luck ! :)
I have a program that makes several requests to a database, opening and closing connections to do what it needs to do. For each connection, it does a select that return 50 results and an update; it does this roughly 10 times per connection. After that, the connection is closed, and a new one is taken. But recently we have been having some random issues in which this SQL exception appears:
java.sql.SQLException: You can't operate on a closed Statement!!!
This error appears randomly. It first appeard mid-execution, and the only moment I managed to reproduce it, it happened at the initiation of the program (when I started it again after that, without making any change, it worked perfectly fine). I've looked around in the code but there's no chance that the connection closes before it can be used (the error occurs while inserting a parameter in a prepared statement). I'm already using c3p0 to manage the connection pool, so I don't know where else to look.
Someone has faced this error before? Any suggestions on where to look or how to reproduce it so I can test it properly?
Edit: Here is the problematic piece of code
try{
//send row to producer
producer.processItem(fields);
if (stmtLasProcessedTransaction == null) {
stmtLasProcessedTransaction = getDbConnection().prepareStatement("UPDATE JTICKET_SUBSCRIBER SET LAST_PROCESSED_ROW = ? WHERE NAME = ? ");
logger.trace("creating statement");
}
//update last processed transaction
logger.trace("Setting the primary key to the prepared statement");
stmtLasProcessedTransaction.setString(1, primaryKey);
logger.trace("Setting the name to the prepared statement");
stmtLasProcessedTransaction.setString(2, name);
logger.trace("Attempting to execute the update on JTICKET_SUBSCRIBER in consumer {}",this.name);
stmtLasProcessedTransaction.executeUpdate();
logger.trace("Commiting execution");
getDbConnection().commit();
logger.trace("Update on JTICKET_SUBSCRIBER in consumer {} executed successfully",this.name);
if (processedRows % 500 == 0) {
logger.trace("resetting prepared statement");
stmtLasProcessedTransaction.close();
logger.trace("statement closed");
stmtLasProcessedTransaction = null;
}
processedRows++;
}catch(SQLException sqlException){
logger.error("An SQL error ocurred while processing consumed item. Closing database connection and statement",sqlException);
try{
stmtLasProcessedTransaction.close();
logger.info("Previous prepared statement of db consumer {} closed",this.name);
}catch(Throwable throwable){
logger.info("Couldn't properly close the prepared statement of db consumer {}",this.name);
}finally{
stmtLasProcessedTransaction=null;
}
try{
databaseConnection.rollback();
logger.info("Rollback of db connection of consumer {} done successfully",this.name);
databaseConnection.close();
logger.info("Previous connection of db consumer {} closed",this.name);
}catch(Throwable throwable){
logger.info("Couldn't rollback and/or close the connection of db consumer {}",this.name);
}finally{
databaseConnection=null;
}
throw sqlException;
}catch(Exception exception){
logger.error("An error ocurred while processing consumed item.", exception);
throw exception;
}
The prepared statement is a local variable, not a function one, so it can be re-used with every loop (this piece is part of a function that is called once for every result in a query that is done with a prepared statement to the same db connection). The error occurs when I'm trying to work on the prepared statement.
And the latest stack:
18/06/15 15:54:34.841 [ecbcbcmt] TRACE DatabaseConsumer - creating statement 18/06/15 15:54:34.850 [ecbcbcmt] ERROR DatabaseConsumer - An
error ocurred while processing consumed item. java.sql.SQLException:
You can't operate on a closed Statement!!! at
com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
~[mchange-commons-java-0.2.9.jar:0.2.9] at
com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
~[mchange-commons-java-0.2.9.jar:0.2.9] at
com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:488)
~[c3p0-0.9.5.jar:0.9.5] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.processRow(DatabaseConsumer.java:152)
[bin/:na] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseNumberConsumer.processRows(DatabaseNumberConsumer.java:73)
[bin/:na] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.start(DatabaseConsumer.java:65)
[bin/:na] at
us.inswitch.jticket.subscriber.consumer.Consumer.run(Consumer.java:35)
[bin/:na] at java.lang.Thread.run(Thread.java:662) [na:1.6.0_38-ea]
Caused by: java.lang.NullPointerException: null at
com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:482)
~[c3p0-0.9.5.jar:0.9.5] ... 5 common frames omitted 18/06/15
15:54:34.852 [ecbcbcmt] WARN DatabaseConsumer - An error ocurred
while consuming table data. DatabaseConsumer will be restarted.
java.sql.SQLException: You can't operate on a closed Statement!!! at
com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:118)
~[mchange-commons-java-0.2.9.jar:0.2.9] at
com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:77)
~[mchange-commons-java-0.2.9.jar:0.2.9] at
com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:488)
~[c3p0-0.9.5.jar:0.9.5] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.processRow(DatabaseConsumer.java:152)
~[bin/:na] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseNumberConsumer.processRows(DatabaseNumberConsumer.java:73)
~[bin/:na] at
us.inswitch.jticket.subscriber.consumer.database.DatabaseConsumer.start(DatabaseConsumer.java:65)
~[bin/:na] at
us.inswitch.jticket.subscriber.consumer.Consumer.run(Consumer.java:35)
[bin/:na] at java.lang.Thread.run(Thread.java:662) [na:1.6.0_38-ea]
Caused by: java.lang.NullPointerException: null at
com.mchange.v2.c3p0.impl.NewProxyPreparedStatement.setString(NewProxyPreparedStatement.java:482)
~[c3p0-0.9.5.jar:0.9.5] ... 5 common frames omitted
It's weird because it's completely random. We've had the program up and running for a while now, with all the connections working perfectly fine, and we get this kind of problem.
Use local variables, or otherwise use PreparedStatements carefully.
This avoids concurrent usage as in a web application.
try (PreparedStatement stmt = conn.prepareStatement(sql)) {
...
try (ResultSet rs = stmt.executeQuery()) {
...
} // rs close
} // Does stm.close()
The try-with-resources also closes when an exception is thrown.
The statement stmtLasProcessedTransaction.close(); is present at two places which is fishy!!
1. within try block in conditional if
2. within catch block
Better programming practice is to have only one close statement, that too in finally block
PS: You can have try-catch-finally within finally block as well
Is there any way to determine database connection pool size (connection in used/connection remaining in connection pool) programmatically? We am using Hibernate with C3P0.
We are facing issues while connecting to db. Following exception is thrown and the data is not saved in db.
1005,MA,19/09/11 09:39:14,com.novosys.gtw.business.frontend.SnapshotMessageBusiness.save, Major: Cannot open connection
org.hibernate.exception.GenericJDBCException: Cannot open connection
at org.hibernate.exception.SQLStateConverter.handledNonSpecificException(SQLStateConverter.java:126)
at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:114)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:52)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:449)
at org.hibernate.jdbc.ConnectionManager.getConnection(ConnectionManager.java:167)
at org.hibernate.jdbc.JDBCContext.connection(JDBCContext.java:142)
at org.hibernate.transaction.JDBCTransaction.begin(JDBCTransaction.java:85)
at org.hibernate.impl.SessionImpl.beginTransaction(SessionImpl.java:1354)
at sun.reflect.GeneratedMethodAccessor6.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.hibernate.context.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:342)
at $Proxy0.beginTransaction(Unknown Source)
at com.novosys.gtw.util.base.BaseBusiness.save(BaseBusiness.java:199)
at com.novosys.gtw.business.backend.receivesnapshotmessage.filter.SaveMessageFilter.decode(SaveMessageFilter.java:102)
at org.apache.mina.filter.codec.demux.DemuxingProtocolCodecFactory$ProtocolDecoderImpl.doDecode(DemuxingProtocolCodecFactory.java:292)
at org.apache.mina.filter.codec.CumulativeProtocolDecoder.decode(CumulativeProtocolDecoder.java:133)
at org.apache.mina.filter.codec.ProtocolCodecFilter.messageReceived(ProtocolCodecFilter.java:158)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at com.novosys.gtw.business.backend.receivesnapshotmessage.filter.WhitelistFilter.messageReceived(WhitelistFilter.java:231)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at com.novosys.gtw.business.backend.receivesnapshotmessage.filter.MoniterFilter.messageReceived(MoniterFilter.java:92)
at org.apache.mina.common.support.AbstractIoFilterChain.callNextMessageReceived(AbstractIoFilterChain.java:299)
at org.apache.mina.common.support.AbstractIoFilterChain.access$1100(AbstractIoFilterChain.java:53)
at org.apache.mina.common.support.AbstractIoFilterChain$EntryImpl$1.messageReceived(AbstractIoFilterChain.java:648)
at org.apache.mina.filter.executor.ExecutorFilter.processEvent(ExecutorFilter.java:220)
at org.apache.mina.filter.executor.ExecutorFilter$ProcessEventsRunnable.run(ExecutorFilter.java:264)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:650)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:675)
at org.apache.mina.util.NamePreservingRunnable.run(NamePreservingRunnable.java:51)
at java.lang.Thread.run(Thread.java:595)
Caused by: java.sql.SQLException: Connections could not be acquired from the underlying database!
at com.mchange.v2.sql.SqlUtils.toSQLException(SqlUtils.java:106)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:529)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:128)
at org.hibernate.connection.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:78)
at org.hibernate.jdbc.ConnectionManager.openConnection(ConnectionManager.java:446)
... 31 more
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:557)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:477)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:525)
... 34 more
We tried to resolve it by increasing connection pool size and also increasing no. of connections available at MySQL level, but of no use. We are now trying to sort of debug it to see if its due to connection pool size or due to MySQL connection size. We want to log no. of connection available/in use in connection pool size but could not get any help from google.
Environment: Java, Hibernate, C3P0, MySQL
Session session = null;
Transaction transaction = null;
try {
session = HibernateUtil.getSessionFactory(datasource).getCurrentSession();
transaction = session.beginTransaction();
// db save called here
session.getTransaction().commit();
} catch (Exception e) {
Logger.write(LoggerConstant.MAJOR_ERROR, e.getMessage(), e, methodName);
} finally {
try {
if ((transaction != null) && (transaction.isActive())) {
transaction.rollback();
}
} catch (Exception e) {
Logger.write(LoggerConstant.CRITICAL_ERROR, e.getMessage(), e, methodName);
}
try {
if ((session != null) && (session.isOpen())) {
session.close();
}
} catch (Exception e) {
Logger.write(LoggerConstant.CRITICAL_ERROR, e.getMessage(), e, methodName);
}
}
I don't believe your problem is the connection pool, per se, but more generally a connection leak. This problem is commonly related to the use of HibernateDaoSupport.getSession() without properly pairing with HibernateDaoSupport.releaseSession(). In general, you want something like
public SomeObject getSomething()
{
Session session = null;
try
{
session = this.getSession();
Query query = session.createSQLQuery("SELECT * FROM SomeTable WHERE SomeClause").addEntity(SomeObject.class);
// extract object from query
return someObject;
}
finally
{
if (session != null)
this.releaseSession(session);
}
}
This can be automated by using a HibernateCallback. You do this by providing the query to this.getHibernateTemplate().executeFind which will use a session in Hibernate with automated resource management.
Apart from what ex0du5 has suggested, the exception trace also suggest following:
Caused by: com.mchange.v2.resourcepool.CannotAcquireResourceException: A ResourcePool could not acquire a resource from its primary factory or source.
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1319)
This implies that the connection pool was not able to acquire new connection FROM DATABASE.
Please check the MySQL log for any errors.
Check the maximum connection pool size and max number of connection setting on mysql configuration. (Its least likely that connection pool size will be more that max connection on mysql configuration, but plz make sure of this)
Also there is a way where in you can monitor all the parameters (including max connection setting) of C3P0 conenction pool.
To properly configure the connection pool size, you need to have metrics to investigate the connection usage patterns.
FlexyPool aims to aid you figuring our the right connection pool size, because it can monitor the following metrics:
concurrent connections histogram
concurrent connection requests histogram
data source connection acquiring time histogram
connection lease time histogram
maximum pool size histogram
total connection acquiring time histogram
overflow pool size histogram
retries attempts histogram
You might check the following articles:
FlexyPool, reactive connection pooling
Professional Connection Pool Sizing
The simple scalability equation
What is Hibernate's responsibility in regards to database connections it gets from an underlying connection pool. Does it test to see if a connection is closed before it uses it? and if so get another connection from the pool?
I've included error and confirmation info below. Any ideas of where I can start to troubleshoot this would be very helpful. And any advice on the SQL Server driver settings we are using.
from the Catalina log:
04-Nov-2010 21:54:52.691 WARNING org.apache.tomcat.jdbc.pool.ConnectionPool.abandon Connection has been abandoned PooledConnection[ConnectionID:8]:java.lang.Exception
at org.apache.tomcat.jdbc.pool.ConnectionPool.getThreadDump(ConnectionPool.java:926)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:681)
at org.apache.tomcat.jdbc.pool.ConnectionPool.borrowConnection(ConnectionPool.java:545)
at org.apache.tomcat.jdbc.pool.ConnectionPool.getConnection(ConnectionPool.java:166)
at org.apache.tomcat.jdbc.pool.DataSourceProxy.getConnection(DataSourceProxy.java:106)
from our application log:
2010-11-04 21:54:52,705 [tomcat-http--18] WARN util.JDBCExceptionReporter - SQL Error: 0, SQLState: 08S01
2010-11-04 21:54:52,707 [tomcat-http--18] ERROR util.JDBCExceptionReporter - Socket closed
2010-11-04 21:54:52,708 [tomcat-http--18] ERROR transaction.JDBCTransaction - JDBC rollback failed
java.sql.SQLException: Connection has already been closed.
at org.apache.tomcat.jdbc.pool.ProxyConnection.invoke(ProxyConnection.java:112)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94)
at org.apache.tomcat.jdbc.pool.interceptor.AbstractCreateStatementInterceptor.invoke(AbstractCreateStatementInterceptor.java:71)
at org.apache.tomcat.jdbc.pool.JdbcInterceptor.invoke(JdbcInterceptor.java:94)
at org.apache.tomcat.jdbc.pool.interceptor.ConnectionState.invoke(ConnectionState.java:132)
at $Proxy38.rollback(Unknown Source)
at org.hibernate.transaction.JDBCTransaction.rollbackAndResetAutoCommit(JDBCTransaction.java:217)
at org.hibernate.transaction.JDBCTransaction.rollback(JDBCTransaction.java:196)
at org.springframework.orm.hibernate3.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:676)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:845)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:822)
at org.springframework.transaction.interceptor.TransactionAspectSupport.completeTransactionAfterThrowing(TransactionAspectSupport.java:412)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:111)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:625)
The configuration:
<Resource defaultAutoCommit="false" defaultReadOnly="false"
defaultTransactionIsolation="SERIALIZABLE"
driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
factory="org.apache.tomcat.jdbc.pool.DataSourceFactory"
fairQueue="false" initialSize="10"
jdbcInterceptors="ConnectionState;StatementFinalizer"
jmxEnabled="true" logAbandoned="true" maxActive="100"
maxIdle="10" maxWait="30000"
minEvictableIdleTimeMillis="10000" minIdle="10"
name="com.ourcompany.ap.shoppingcart/datasource"
password="somePassword" removeAbandoned="true"
removeAbandonedTimeout="60" testOnBorrow="true"
testOnReturn="false" testWhileIdle="false"
timeBetweenEvictionRunsMillis="5000"
type="javax.sql.DataSource"
url="jdbc:sqlserver://approd\approd;databaseName=prod"
useEquals="false" username="AccessPointNet"
validationInterval="30000" validationQuery="SELECT 1"/>`
I had a similar problem which was solved by increasing the removeAbandonedTimeout value to a higher number. The problem we faced was due to the query which took longer time that the above mentioned timeout.
What is Hibernate's responsibility in regards to database connections it gets from an underlying connection pool.
Not much, releasing it when the Session gets closed.
Does it test to see if a connection is closed before it uses it? and if so get another connection from the pool?
No, Hibernate doesn't, checking the validity of connection(s) is the responsibility of a connection pool if you want to.
I've included error and confirmation info below. Any ideas of where I can start to troubleshoot this would be very helpful.
What kind of process are you running exactly? A long transaction? Does it timeout? What does the Caused by: say? About the trace:
2010-11-04 21:54:52,705 [tomcat-http--18] WARN util.JDBCExceptionReporter - SQL Error: 0, SQLState: 08S01
2010-11-04 21:54:52,707 [tomcat-http--18] ERROR util.JDBCExceptionReporter - Socket closed
2010-11-04 21:54:52,708 [tomcat-http--18] ERROR transaction.JDBCTransaction - JDBC rollback failed java.sql.SQLException: Connection has already been closed.
Can you reproduce it in a deterministic way? Any networking problem?
And any advice on the SQL Server driver settings we are using.
I've added a great resource about Tomcat and connection pool configuration below. Not specific to SQL Server though.
Resources
Configuring jdbc-pool for high-concurrency
We usually work around this by using dbcp, and providing a validationQuery when definining our data source. Then, dbcp will verify the usability of pooled connections by issuing that query (and transparently recreate the connection should it no longer work), prior to returning them to the application.
Check out
http://tomcat.apache.org/tomcat-6.0-doc/jndi-datasource-examples-howto.html
for more details.
I am currently using liquibase(v1.9) in my project, and when the changeSets run against a blank schema it always takes longer than 60 seconds which results in the thread being marked abandoned I'm not thrilled with increasing the removeAbandonedTimeout value, but this is the only solution I've been able to find to prevent this issue; however, after the initial schema population is complete this is seldom a problem so I set the value back to 60 seconds.
I worked on an issue in the past where we weren't returning connections back to the pool correctly. So, when a connection was used and not returned, making a database call when it was timing out would throw an exception.
We were able to reproduce the issue by making a call to the database, waited 8 hours (postgres' default time out) and tried to make a call to the database again. It throw the same exception every time. Our solution was to rethink (or better yet, add) a connection management strategy.
So, to sum up, are you actually returning your connections to the pool by closing the Session?
I got the solution for the above exception.
Just close the instance of session factory as well while closing the session .
Look at the below Code:
public class HibernateUtil {
private static final SessionFactory sessionFactory = buildSessionFactory();
private static SessionFactory buildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
return new Configuration().configure("hibernate.cfg.xml").buildSessionFactory();
}
catch (Throwable ex) {
ex.printStackTrace();
// Make sure you log the exception, as it might be swallowed
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
public static SessionFactory getSessionfactory() {
return sessionFactory;
}
public static Session getSession() {
Session session=sessionFactory.openSession();
session.getTransaction().begin();
return session;
}
public static void closeSession(Session session) {
if(session!=null )
{
if(session.getTransaction().isActive())
{
session.getTransaction().commit();
}
session.close();
getSessionfactory().close();
}
}
}
just call the method HibernateUtil.closeSession(). This will solve the problem.