Hi Everyone,
First of all, since this forum is a real monster I would ask for an apology if this problem has been already solved, please just link me to the correct Thread and I will read there.
I am experiencing the following situation and the problem is as follows:
I have a POJO application which uses hibernate to save massive amounts of data received by different sources. The POJO uses Hibernate and C3P0 configured via the hibernate.cfg.xml file.
The POJO will spawn first a certain amount of threads (depending on the amount of sources) which each is connected to the source where the information is coming and which has to be saved on a database.
Each of these threads will spawn another thread lets say every 2 seconds (user defined) which will process a list of data retrieved from the connected sources and then save it to the database.
You can see that this is pretty data intensive and I am doing lots of connections to the database to save all this data.
The POJO is using the following configuration and HibernateUtil which uses the getCurrentSession to get a session binded to each Thread:
hibernate.cfg.xml
Code:
<!-- configuration pool via c3p0 -->
<property name="c3p0.acquire_increment">1</property>
<property name="c3p0.idle_test_period">3600</property>
<property name="c3p0.timeout">7200</property>
<property name="c3p0.max_size">5</property>
<property name="c3p0.min_size">5</property>
<property name="c3p0.max_statements">0</property>
<property name="c3p0.preferredTestQuery">select 1;</property>
<property name="hibernate.connection.provider_class">org.hibernate.connection.C3P0ConnectionProvider</property>
<!-- JDBC connection pool (use the built-in) -->
<!-- <property name="connection.pool_size">1</property> -->
<!-- SQL dialect -->
<property name="dialect">org.hibernate.dialect.MySQLDialect</property>
<!-- Enable Hibernate's automatic session context management -->
<property name="current_session_context_class">thread</property>
<!-- Disable the second-level cache -->
<property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property>
<!-- Echo all executed SQL to stdout
<property name="show_sql">true</property>
-->
<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create</property>
As you can see pretty straight forward..
the HibernateUtil looks like this
Code:
public class HibernateUtil {
private static SessionFactory sessionFactory;
static {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed. " + ex);
throw new ExceptionInInitializerError(ex); //Critical error automatically exit the SW
}
}
// Create a session everytime it is required
// hibernate will automatically manage the transactions when one or more threads
// are running simultaneously.
public static Session getSession() throws HibernateException{
if (sessionFactory == null)
{
rebuildSessionFactory();
}
// open the session again
Session session = (sessionFactory != null) ? sessionFactory.getCurrentSession(): null;
session.beginTransaction();
return session;
}
// Rebuild hibernate session factory
public static void rebuildSessionFactory() {
try {
// Create the SessionFactory from hibernate.cfg.xml
sessionFactory = new Configuration()
.configure()
.buildSessionFactory();
} catch (Throwable ex) {
System.err.println("Initial SessionFactory creation failed." + ex);
throw new ExceptionInInitializerError(ex);
}
}
//Close the single hibernate session instance.
public static void closeSession(Session session) throws HibernateException {
if (session != null)
{
try
{
session.getTransaction().commit();
}
catch(HibernateException e)
{
//if an error occurrs commiting then
// rollback and close session
e.printStackTrace();
session.getTransaction().rollback();
}
}
}
public static SessionFactory getSessionFactory() {
return sessionFactory;
}
}
So no big deal up to now,
In order to save the data in the database I open a session , begin transaction, save data, commit (session get closed automatically) and so on, I do not keep sessions open for a long time or open one session for a big packet of data. In other words I am not doing any batch save.
So when I run the application I have the following behavior which depends on the number of connection that I AM POOLING in C3P0:
Lets say that I indicate C3P0 that I want a maximum of 5 connections pool.
In that case the following happens:
As the application starts, lets say the first 5 connections get opened, data is saved (5 records) and at that point everything collapses.... the Application and Threads keep running but no data is saved on the database, even though when I look at the mySQL administrator I see that there are 5 connections open and FREE to USE, NO LOCKS, or something close to that.
The application keeps running and via debug I noticed that in HibernateUtil the session (getCurrentSession) gets created but when I reach the point "session.beginTransaction()" something happens (I have tried like mad to get an exception from it JDBCException, HibernateException,Exception, nothing gets me information) and the transactions does not get opened.
So after lots of trial and errors I discovered the following:
If I set the c3p0 connection pool much much bigger like lets say 50 connection pools, THINGS WORK, that means I do not see this strange behaviour, up to some point, because some but not all data I want to save to the database DOES NOT GET SAVED.
So I continued to research on this direction and since I dont know how much is managed by the hibernate+c3p0 combo I cannot really know If this is something I am missing that I have to do by myself or if it is a bug or whatever:
So my thesis is the following:
It looks like when I try to open a connection when all connections in the c3p0 pool are being used the session.beginTransaction() or better said the session (which opens the connection when it is needed) DOES NOT WAIT until a connection is made available BUT it JUST abort the session without any notice to me (since I cannot catch the exception).
My expectation was that hibernate or C3P0, was intelligent enough to put a session on hold until a connection in the pool is freed and then give the connection to this waiting session once is free.
As I said, I do not know in detail all the inner workings of Hibernate and c3p0 so before I make a move to solve this problem I would like to know what do you think about this and what are the possible solutions to this problem.
I will be kindly waiting for your reply and I thank you very much in advance for all the help you can provide to me.
Thank you
Gustav