c3p0 DataSource monitor deadlock - all threads hang - how to fix - mysql

We have a Spring based application and recently we went into production. We are using Spring #Controller that ultimately hit DAOs that use JDBCTemplate. It is using c3p0's ComboPooledDataSource
On an increased load (something like 150 concurrent users), the application hangs for all users - the DataSource gets locked by something - on a thread dump, there are like 200 threads that say - obviously the DataSource is deadlocked.
"http-bio-8080-exec-440" - Thread t#878
java.lang.Thread.State: WAITING
at java.lang.Object.wait(Native Method)
- waiting on <146d984e> (a com.mchange.v2.resourcepool.BasicResourcePool)
at com.mchange.v2.resourcepool.BasicResourcePool.awaitAvailable(BasicResourcePool.java:1418)
at com.mchange.v2.resourcepool.BasicResourcePool.prelimCheckoutResource(BasicResourcePool.java:606)
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:526)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:756)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:683)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.springframework.jdbc.datasource.DataSourceUtils.doGetConnection(DataSourceUtils.java:111)
at org.springframework.jdbc.datasource.DataSourceUtils.getConnection(DataSourceUtils.java:77)
at org.springframework.jdbc.core.JdbcTemplate.execute(JdbcTemplate.java:573)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:637)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:666)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:674)
at org.springframework.jdbc.core.JdbcTemplate.query(JdbcTemplate.java:718)
After that point the application becomes unusable unless restarted. When this happened DBA team didn't observe any load on the database.
At that time c3p0 was configured like that:
app_en.driverClass=com.mysql.jdbc.Driver
app_en.user=tapp_en
app_en.password=tapp_en
app_en.jdbcUrl=jdbc:mysql://10.10.0.102:3306/tapp_en?useUnicode=true&characterEncoding=utf-8&autoReconnect=true
app_en.acquireIncrement=5
app_en.maxIdleTime=3600
app_en.maxIdleTimeExcessConnections=300
app_en.unreturnedConnectionTimeout=3600
app_en.numHelperThreads=6
app_en.minPoolSize=20
app_en.maxPoolSize=100
app_en.idleConnectionTestPeriod=120
app_en.testConnectionOnCheckin=true
After that, I changed c3p0's configuration as follows - and enabled DEBUG logging for com.mchange.v2.c3p0 package:
app_en.driverClass=com.mysql.jdbc.Driver
app_en.user=tapp_en
app_en.password=tapp_en
app_en.jdbcUrl=jdbc:mysql://10.10.0.102:3306/tapp_en? useUnicode=true&characterEncoding=utf-8&autoReconnect=true
app_en.acquireIncrement=5
app_en.maxIdleTime=180
app_en.maxIdleTimeExcessConnections=60
app_en.unreturnedConnectionTimeout=30
app_en.checkoutTimeout=10000
app_en.numHelperThreads=12
app_en.debugUnreturnedConnectionStackTraces=true
app_en.initialPoolSize=10
app_en.maxPoolSize=100
app_en.idleConnectionTestPeriod=120
app_en.preferredTestQuery="select 1 from tbl_users"
With this configuration in place, I again ran load tests and the application still hanged... although the threads recover after they are unable to obtain connection to the database. Even though, the game hanged for too many users even though the threads recovered unlike the previous configuration - so they had to restart their clients.
Although all logging was enabled, the c3p0 logs don't log any deadlock messages. The error messages I see are just that:
[06/24/2015 12:20:54] [C3P0PooledConnectionPoolManager[identityToken->1oed6dl9a9ak8qsgqfvdu|4d6145af]-HelperThread-#10] DEBUG NewPooledConnection - com.mchange.v2.c3p0.impl.NewPooledConnection#7f0bc55a closed by a client.
java.lang.Exception: DEBUG -- CLOSE BY CLIENT STACK TRACE
at com.mchange.v2.c3p0.impl.NewPooledConnection.close(NewPooledConnection.java:659)
at com.mchange.v2.c3p0.impl.NewPooledConnection.closeMaybeCheckedOut(NewPooledConnection.java:255)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool$1PooledConnectionResourcePoolManager.destroyResource(C3P0PooledConnectionPool.java:621)
at com.mchange.v2.resourcepool.BasicResourcePool$1DestroyResourceTask.run(BasicResourcePool.java:1024)
at com.mchange.v2.async.ThreadPoolAsynchronousRunner$PoolThread.run(ThreadPoolAsynchronousRunner.java:696)
There aren't any transactions in the application made, nor are we using any TransactionManager or TransactionTemplate. I wonder if this may be some kind of bug in the frameworks used, or misconfiguration. These are the relevant frameworks used:
c3p0-0.9.5-pre8
mysql-connector-java-5.1.24
spring-core-3.2.1.RELEASE
spring-web-3.2.1.RELEASE
mchange-commons-java-0.2.7
We really appreciate any help because this is blocking our efforts to release our product.
P.S. EDIT: Here is the configuration of the DataSource:
<bean id="app_en_DataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass" value="${app_en.driverClass}" />
<property name="jdbcUrl" value="${app_en.jdbcUrl}" />
<property name="user" value="${app_en.user}" />
<property name="password" value="${app_en.password}" />
<property name="acquireIncrement" value="${app_en.acquireIncrement}"></property>
<property name="maxIdleTime" value="${app_en.maxIdleTime}"></property>
<property name="maxIdleTimeExcessConnections" value="${app_en.maxIdleTimeExcessConnections}"></property>
<property name="unreturnedConnectionTimeout" value="${app_en.unreturnedConnectionTimeout}"></property>
<property name="checkoutTimeout" value="${app_en.checkoutTimeout}"></property>
<property name="numHelperThreads" value="${app_en.numHelperThreads}"></property>
<property name="debugUnreturnedConnectionStackTraces" value="${app_en.debugUnreturnedConnectionStackTraces}"></property>
<property name="initialPoolSize" value="${app_en.initialPoolSize}"></property>
<property name="maxPoolSize" value="${app_en.maxPoolSize}"></property>
<property name="idleConnectionTestPeriod" value="${app_en.idleConnectionTestPeriod}"></property>
<property name="preferredTestQuery" value="${app_en.preferredTestQuery}"></property>
</bean>
And here is some code inside the application that isn't using the jdbcTemplate directly. There is nothing else that does that, everything else is jdbcTemplate.update, jdbcTemplate.query:
Connection conn = null;
ResultSet getItemsRS = null;
try {
JdbcTemplate jdbcTemplate = getJdbcTemplate(database);
conn = jdbcTemplate.getDataSource().getConnection();
UserItems items;
if (!action.areItemsNew()) {
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
PreparedStatement getItemsPS = conn.prepareStatement("select * from tbl_items where ownerId = ? for update",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
getItemsPS.setLong(1, userId);
getItemsRS = getItemsPS.executeQuery();
getItemsRS.next();
items = new UserItemsRowMapper().mapRow(getItemsRS, getItemsRS.getRow());
} else {
items = new UserItems();
}
action.doUserItemsAction(items);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(items.getItemContainers());
oos.close();
byte[] data = baos.toByteArray();
Blob blob = conn.createBlob();
blob.setBytes(1, data);
if (!action.areItemsNew()) {
getItemsRS.updateBlob("data", blob);
getItemsRS.updateRow();
} else {
jdbcTemplate.update("insert into tbl_items(ownerId,data) values(?,?)", userId, data);
}
} catch (Exception e) {
logger.error(e);
throw new RuntimeException(e);
} finally {
if (!action.areItemsNew()) {
try {
conn.commit();
conn.close();
} catch (SQLException e) {
logger.error(e);
throw new RuntimeException(e);
}
}
}
The reason for this code is that I would like to block reading/writing to the user's items before they are updated by this operation action.doUserItemsAction(items) as written above.

The code you have is potentially dangerous and has a connection leak, when checking out a connection yourself you should always close it, there might be a case it fails to close the connection.
Instead I strongly suggest using Spring to manage your transactions and connections.
First annotate your method with #Transactional(isolation=SERIALIZABLE). Next add a DataSourceTransactionManager and <tx:annotation-driven /> to your configuration. After these changes rewrite the data access code you have.
JdbcTemplate jdbcTemplate = getJdbcTemplate(database);
final UserItems items;
if (!action.areItemsNew()) {
items = jdbcTemplate.queryForObject("select * from tbl_items where ownerId = ? for update", userId, new UserItemsRowMapper());
} else {
items = new UserItems();
}
action.doUserItemsAction(items);
String query = !action.areItemsNew() ? "update tbl_items set data=? where ownerId=?" : "insert into tbl_items(data,ownerId) values(?,?)";
byte[] data = SerializationUtils.serialize(items.getItemContainers());
jdbcTemplate.update(query, new SqlLobValue(data), userId);
Something like that (together with the aformentioned modification should work). (This was more or less from the top of my head, so it might need some tweaking). The use of proper transaction management ensures that everything is reusing the same single connection instead of multiple connections, it also ensures that a connection is returned to the pool when finished or when something goes wrong.
I would still suggest a different datasource as C3P0 is pretty old.

So, a few things.
1) The "error" messages that you see are not errors, when c3p0 logs an Exception whose message begins with DEBUG, that means you are logging at DEBUG levels and c3p0 has generated the Exception just to capture the stack trace. (c3p0 is an old library; Thread.getStackTrace() didn't exist back in the day, creating an Exception was a convenient way to capture and dump the stack.) You are just logging the expected destruction of pooled Connections due to expiration or test failures. In general, c3p0 expects to log at INFO, it will be very verbose at DEBUG levels.
2) You are not deadlocking c3p0's Thread pool. If you were, you'd see APPARENT DEADLOCK messages and then recoveries. You are experiencing a condition of pool exhaustion: clients are awaiting Connections, but the pool is at maxPoolSize and unable to acquire them.
3) The usual cause of pool exhaustion is a Connection leak: Somewhere in your application's code path, under some (probably Exceptional) circumstances, Connections are acquired and then never close()ed. You need to be very careful to ensure that Connections are reliably close()ed in finally blocks in ways that cannot be skipped due to prior failures within the finally block. In Java 7+, use try-with-resources. In older versions, use the reliable resource cleanup idiom.
4) To test whether a Connection leak is the issue, set the c3p0 config params unreturnedConnectionTimeout and debugUnreturnedConnectionStackTraces. unreturnedConnectionTimeout will work around the problem, but yuck. More importantly, debugUnreturnedConnectionStackTraces will show you where the problem is so that you can fix it, logging the stack trace that opened the unclosed Exception at INFO. (You must set unreturnedConnectionTimeout for debugUnreturnedConnectionStackTraces to have any effect; the stack trace is logged when a Connection times out as abandoned.)
5) Although 0.9.5-pre8 is probably ok, the current production version of c3p0 is c3p0-0.9.5.1 (which depends upon mchange-commons-java v.0.2.10). You might think about using that. I don't think it has anything at all to do with your issue, but still.
I hope this helps!
Update: Since you've now posted code that shows the likely Connection leak, here's a suggestion for how to fix it. Replace your finally block with:
} finally {
if ( conn != null ) {
try { if (!action.areItemsNew()) conn.commit(); }
catch (SQLException e) {
logger.error(e);
throw new RuntimeException(e);
} finally {
conn.close()
}
}
}
Update 2: The redone finally block above will solve the Connection leak, but if I were you I'd also change the logic of this code regarding commit(). Here's a suggested revision:
Connection conn = null;
ResultSet getItemsRS = null;
try {
JdbcTemplate jdbcTemplate = getJdbcTemplate(database);
conn = jdbcTemplate.getDataSource().getConnection();
UserItems items;
if (!action.areItemsNew()) {
conn.setAutoCommit(false);
conn.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
PreparedStatement getItemsPS = conn.prepareStatement("select * from tbl_items where ownerId = ? for update",
ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
getItemsPS.setLong(1, userId);
getItemsRS = getItemsPS.executeQuery();
getItemsRS.next();
items = new UserItemsRowMapper().mapRow(getItemsRS, getItemsRS.getRow());
} else {
items = new UserItems();
}
action.doUserItemsAction(items);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(items.getItemContainers());
oos.close();
byte[] data = baos.toByteArray();
Blob blob = conn.createBlob();
blob.setBytes(1, data);
if (!action.areItemsNew()) {
getItemsRS.updateBlob("data", blob);
getItemsRS.updateRow();
conn.commit();
} else {
jdbcTemplate.update("insert into tbl_items(ownerId,data) values(?,?)", userId, data);
}
} catch (Exception e) {
logger.error(e);
throw new RuntimeException(e);
} finally {
try { if ( conn != null ) conn.close(); }
catch ( Exception e )
{ logger.error(e); }
}
Now commit() will get called only if (!action.areItemsNew()) AND all expected operations have succeeded. Before commit() would get called even if something went wrong. The resource cleanup code is much simpler and cleaner too. Note that in the suggested version, if there's an Exception on close() it's logged, but it is not wrapped and rethrown as a RuntimeException. Usually if there's an Exception on close(), there will have been a more informative Exception prior and that's the one you want to see. If the only place an Exception occurs is on close(), it means that all database operations have succeeded so your application can proceed correctly despite the fault. (If there are lots of Exceptions on close(), eventually you'd exhaust the Connection pool, but in practice that would happen only if there's something badly wrong with your database or network.)

Related

Entity Framework BeginTransaction with Isolation level but no working

I'm building database by using mysql connector with EF6.
Way to handling concurrency updates happens.
Client A updates row
Client B come in updates same row
Client B need to wait Client A commit his updates.
Codes:
using (myEntities db = new myEntities ())
{
db.Database.Connection.Open();
try
{
using (var scope = db .Database.BeginTransaction(System.Data.IsolationLevel.Serializable))
{
{
var test = db.customer_table.Where(x => x.id == 38).FirstOrDefault();
test.bank_holder_name = "CLIENT A";
db.SaveChanges();
scope.Commit();
}
}
}
catch (Exception ex)
{
throw;
}
}
While debugging, I purposely pause when Client A doing this SaveChanges() step.
But Client B can finish his updates without any wait.
Anyone here is experiencing this issue?
P/S: I did a lot reading and trial about Entity Framework concurrency issue, like;
a) Optimistic locking with row_version (Not working perfectly if the timestamp not unique enough to catch concurrency)
b) Transaction Scope (Still the same as result above)
Anyone here have idea to stop concurrency in Entity Framework? Thanks in Advance!

Why am I getting "too many connections" error

I am creating java EE app with Tomcat and MySQL. In hibernate.cfg.xml file I have set connection pool size to 10
<property name="connection.pool_size">10</property>
I have also created a DAO:
public Rules getRulesById(int id) {
Rules rules;
factory = new Configuration().configure().buildSessionFactory();
Session session = factory.openSession();
try {
Query query = session.createQuery("SELECT a FROM Rules a WHERE a.id=:id");
query.setParameter("id", id);
rules = (Rules) query.getSingleResult();
} catch (Throwable ex) {
System.err.println("Failed to create sessionFactory object." + ex);
throw new ExceptionInInitializerError(ex);
} finally {
session.close();
}
return rules;
}
After querying the database about 30 times or so, I get the error:
SEVERE: Servlet.service() for servlet [Jersey Web Application] in context with path [/GoTown] threw exception [org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]] with root cause
java.sql.SQLNonTransientConnectionException: Data source rejected establishment of connection, message from server: "Too many connections"
I am not sure why, I am closing the session with: session.close();
Thanks!

vert.x async jdbc doesn't close connections

I'm implementing a RESTful API with Vert.x. I used its async jdbc client with MySQL and c3p0 as connection pool.
My problem is that although the closeConnection handler is successful, the actual database connection is not closed and reused. The pool gets full in seconds, resulting in: BasicResourcePool:204 - acquire test -- pool is already maxed out. [managed: 20; max: 20]
client.getConnection(connectionAsyncResult -> {
SQLConnection connection = connectionAsyncResult.result();
connection.queryWithParams("SELECT * FROM AIRPORTS WHERE ID = ?", new JsonArray().add(id), select -> {
ResultSet resultSet = select.result();
Airport $airport = resultSet.getRows()
.stream()
.map(Airport::new)
.findFirst()
.get();
asyncResultHandler.handle(Future.succeededFuture($airport));
connection.close(closeHandler -> {
if (closeHandler.succeeded()) {
LOG.debug("Database Connection closed");
}
else if (closeHandler.failed()) {
LOG.error("Database Connection failed to close!");
}
});
});
});
Any idea what I'm missing?
All the best!
You're probably facing some exception in your handler, if such thing happens, then the last line will not be executed, therefore the close is not called and the connection returned to the pool.
You should wrap your code with a try finally block to guarantee the connection is returned to the pool.

Hibernate using C3P0 Works fine on Oracle but does not close connection with MySQL 5.6

I am using Servlet 2.4, Hibernate 4.2.4 Final, c3p0 0.9.2.1, Tomcat 7.0.42, MySQL 5.6 & JSP.
I had completed development using Oracle 11gR2 DB but at a later point was asked to switch to MySQL as the Database.
I have a rather unusual problem at hand.
The problem is Multiple MySQL Process/Connections being created for every single DB request, which are neither closed nor returned to the pool despite issuing the SessionFactoryUtil.close(); which was not the case with Oracle DB.
I tested the exact same code on these two different Databases, i.e after executing a Function/Request (ex: Login)
The application when tested with Oracle (11gR2) the DB created a single connection and used it for all requests henceforth.
SELECT * FROM V$RESOURCE_LIMIT
Gives me the following Output
RESOURCE_NAME: processes
CURRENT_UTILIZATION: 32
MAX_UTILIZATION: 36
INITIAL_ALLOCATION: 300
LIMIT_VALUE: 300
No matter how many users log in the Connection pool maintains it gracefully.
Now on the other hand when the same application was run on MySQL:
I did a SHOW PROCESSLIST; on MySQL which shows two processes being created for every request; c3p0 successfully terminates one connection but the other connection remains till the DB crashes because it exceeded the max connections available.
My SessionFactoryUtil is quite simple and straightforward and is as follows:
public class SessionFactoryUtil {
private static SessionFactory sessionFactory;
public static SessionFactory getSessionFactory() {
return sessionFactory = new Configuration().configure()
.buildSessionFactory();//deprecated method not changed due to official reason
}
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
public static void close() {
if (sessionFactory != null) {
sessionFactory.close();
}
sessionFactory = null;
}
My DAO Method is as follows
public User getUserByName(String userName) throws FetchException {
User user = null;
Session session = SessionFactoryUtil.getSessionFactory().getCurrentSession();
try {
session.beginTransaction();
user = (User) session.createQuery("from User where userName = '" + userName + "'").uniqueResult();
} catch (Exception e) {
logger.info("UserDaoImpl -> getUserByName() : Error : " +e);
e.printStackTrace();
} finally {
SessionFactoryUtil.close();
}
return user;
The stack trace where c3p0 destroys a connection is as follows:
20:45:43,692 INFO com.mchange.v2.resourcepool.BasicResourcePool:1493 - A checked-out resource is overdue, and will be destroyed: com.mchange.v2.c3p0.impl.NewPooledConnection#61f31fff
20:45:43,692 INFO com.mchange.v2.resourcepool.BasicResourcePool:1496 - Logging the stack trace by which the overdue resource was checked-out.
java.lang.Exception: DEBUG STACK TRACE: Overdue resource check-out stack trace.
at com.mchange.v2.resourcepool.BasicResourcePool.checkoutResource(BasicResourcePool.java:555)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutAndMarkConnectionInUse(C3P0PooledConnectionPool.java:755)
at com.mchange.v2.c3p0.impl.C3P0PooledConnectionPool.checkoutPooledConnection(C3P0PooledConnectionPool.java:682)
at com.mchange.v2.c3p0.impl.AbstractPoolBackedDataSource.getConnection(AbstractPoolBackedDataSource.java:140)
at org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider.getConnection(C3P0ConnectionProvider.java:84)
at org.hibernate.internal.AbstractSessionImpl$NonContextualJdbcConnectionAccess.obtainConnection(AbstractSessionImpl.java:292)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.obtainConnection(LogicalConnectionImpl.java:214)
at org.hibernate.engine.jdbc.internal.LogicalConnectionImpl.getConnection(LogicalConnectionImpl.java:157)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.doBegin(JdbcTransaction.java:67)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.begin(AbstractTransactionImpl.java:160)
at org.hibernate.internal.SessionImpl.beginTransaction(SessionImpl.java:1426)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.hibernate.context.internal.ThreadLocalSessionContext$TransactionProtectionWrapper.invoke(ThreadLocalSessionContext.java:352)
at com.sun.proxy.$Proxy7.beginTransaction(Unknown Source)
at com.demo.access.impl.ConfDaoImp.showAllEvents(ConfDaoImp.java:939)
at com.demo.business.impl.ConfServiceImpl.showAllEvents(ConfServiceImpl.java:404)
at com.demo.controller.UserController.getControls(UserController.java:112)
at com.demo.controller.UserController.validateUser(UserController.java:93)
at com.demo.controller.UserController.process(UserController.java:42)
at com.demo.controller.ApplicationServlet.process(ApplicationServlet.java:75)
at com.demo.controller.ApplicationServlet.doPost(ApplicationServlet.java:53)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:641)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:722)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:304)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at com.demo.controller.LoginFilter.doFilter(LoginFilter.java:37)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:224)
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:185)
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:151)
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:929)
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:405)
at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:269)
at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:515)
at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:302)
at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)
I have read almost all the question related to this particular scenario but none seems to work, or the thread was abandoned half way, or I am missing out something; could some one please help me get through with this.
This piece of your code did the trick for me:
public static void close() {
if(sessionFactory instanceof SessionFactoryImpl) {
SessionFactoryImpl sf = (SessionFactoryImpl)sessionFactory;
ConnectionProvider conn = sf.getConnectionProvider();
if(conn instanceof C3P0ConnectionProvider) {
((C3P0ConnectionProvider)conn).close();
}
}
sessionFactory.close(); }
Until then Tomcat had (correctly) complained about memory leaks at each hot deployment. Thanks!
a few ideas:
1) you are never closing the Session you create (implicitly by asking for a "current session"). that's a straightforward reason why you might have an unreturned Connection that eventually times out.
2) you are treating your SessionFactory like a Session, building up then tearing down the whole thing (which includes a Connection pool) just to get and use one Connection. not so good. your SessionFamily should have a long lifecycle, your sessions should be for one-time, short-term use.
Its been a while since I found out the answer to my strange problem and I thought that sharing it would help most.
To start with, A couple of things i did wrong was...
Firstly, I migrated from hibernate 3.6 to 4.2 and on doing so I was still using the deprecated buildSessionFactory() method.
Secondly, I was using SessionFactoryUtil.close() after the end of each query statement in my DAO, which defeats the purpose of using Connection Pooling.
Finally, The strange issue where Oracle seems to close the connection successfully after execution of a statement whereas MySql was unable to close the same still remains a mystery.
This, I suspect happened because I was asking SessionFactoryUtil to close a connection which was originally opened by C3P0ConnectionProvider (which I believe was in-turn causing the connection leaks).
After a lot of research and looking around I re-wrote the SessionFactoryUtil as follows...
public class SessionFactoryUtil {
private static SessionFactory sessionFactory;
private static ServiceRegistry serviceRegistry;
public static SessionFactory getSessionFactory() {
Configuration configuration = new Configuration();
configuration.configure();
serviceRegistry = new ServiceRegistryBuilder().applySettings(configuration.getProperties()).buildServiceRegistry();
sessionFactory = configuration.buildSessionFactory(serviceRegistry);
return sessionFactory;
}
public static Session getCurrentSession() {
if(sessionFactory == null){
getSessionFactory();
}
return sessionFactory.getCurrentSession();
}
public static void close() {
if(sessionFactory instanceof SessionFactoryImpl) {
SessionFactoryImpl sf = (SessionFactoryImpl)sessionFactory;
ConnectionProvider conn = sf.getConnectionProvider();
if(conn instanceof C3P0ConnectionProvider) {
((C3P0ConnectionProvider)conn).close();
}
}
sessionFactory.close();
}
Note that all my connections are opened by C3P0ConnectionProvider so it is only logical to close it using C3P0ConnectionProvider itself.
The following is my hibernate.cfg.xml along with c3p0 settings.
<!-- Database connection settings -->
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/application</property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">root</property>
<property name="show_sql">true</property>
<property name="format_sql">false</property>
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="hibernate.current_session_context_class">thread</property>
<property name="hibernate.connection.release_mode">auto</property>
<!-- Create or update the database schema on startup -->
<property name="hibernate.hbm2ddl.auto">none</property>
<!-- DEPRECATED -->
<!-- <property name="connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property> -->
<!-- C3p0 connection pooling configuration -->
<property name="hibernate.connection.provider_class">org.hibernate.service.jdbc.connections.internal.C3P0ConnectionProvider</property>
<property name="c3p0.unreturnedConnectionTimeout">600</property>
<property name="c3p0.debugUnreturnedConnectionStackTraces">false</property>
<!-- configuration pool via c3p0 -->
<property name="c3p0.acquire_increment">1</property>
<property name="c3p0.idle_test_period">600</property>
<property name="c3p0.max_size">75</property>
<property name="c3p0.max_statements">5</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.timeout">600</property>
<property name="c3p0.checkoutTimeout">6000000</property>
<property name="c3p0.testConnectionOnCheckout">false</property>
<property name="c3p0.testConnectionOnCheckin">true</property>
<!-- Mapping -->
</session-factory>
This is again one of the methods from my DAO Class...
public User getUserByName(String userName) throws FetchException {
User user = null;
Session session = SessionFactoryUtil.getCurrentSession();
try {
session.beginTransaction();
user = (User) session.createQuery("from User where userName = '" + userName + "'").uniqueResult();
session.getTransaction().commit();
} catch (Exception e) {
logger.info("UserDaoImpl -> getUserByName() : Error : " +e);
e.printStackTrace();
} finally {
}
return user;
Note that in my DAO at the finally block i don't have to close my connection any more I let c3p0 handle the connection pool.
And voila...!! The Application runs!!! Had more than 2000 transaction hits on a single day in a span of 2 hours.
I hope this helps noob hibernate users like me.

What is the proper way to ensure EntityManager connections are closed?

There are 19 methods in our DAO layer, each is some variation of this:
public TicketProp saveTicketProp(TicketProp prop) {
EntityManager em = this.emf.createEntityManager();
try {
em.getTransaction().begin();
prop = (TicketProp) em.merge(prop);
em.getTransaction().commit();
return prop;
} finally {
em.close();
}
}
Meaning: In each method we handle our own transaction and close it in a finally block. We're testing a Jersey app, so our JUnit tests extend JerseyTest. Each test method instantiates a Grizzly container, runs the test, then shuts down the container. EntityManagerFactory is injected by spring. We're using JPA over Hibernate.
I'm monitoring the connections to our MySQL test DB and they're always high. One test alone runs the MySQL "Max_used_connections" variable to 38. For fun, I went and commented out all the em.close() calls, and the test still uses 38 connections.
I'm using Hibernate's built-in connection pooling (not for prod use, I know). I still expected some sort of intelligent pooling.
Am I handling the EntityManager wrong? How else can I close connections?
You should close the EntityManagerFactory at the end of your test. From the javadoc of EntityManagerFactory#close():
void javax.persistence.EntityManagerFactory.close()
Close the factory, releasing any resources that it holds. After a factory instance has been closed, all methods invoked on it will throw the IllegalStateException, except for isOpen, which will return false. Once an EntityManagerFactory has been closed, all its entity managers are considered to be in the closed state.
As a side note, you should actually rollback the transaction before closing the EM in the finally clause:
public TicketProp saveTicketProp(TicketProp prop) {
EntityManager em = this.emf.createEntityManager();
try {
em.getTransaction().begin();
prop = (TicketProp) em.merge(prop);
em.getTransaction().commit();
return prop;
} finally {
if (em.getTransaction().isActive()) {
em.getTransaction().rollback();
}
if (em.isOpen()) {
em.close();
}
}
}
Why do you think that EntityManager.close() always physically closes underlying connection? It's up to connection pool (you probably need to configure it and set the maximum number of simultaneously open connections).