Close SessionFactory in Hibernate 4.3
hibernate, java
Solution
You're right, there appears to be a bug in Hibernate 4.3.x in which a thread spawned by Hibernate's default connection pool doesn't get cleaned up on shutdown. I filed a bug here (please vote!):
https://hibernate.atlassian.net/browse/HHH-8896
Until it's fixed, you have two choices. You can add a method to your HibernateUtil and use it to force the connection pool to clean itself up at the end of your app's execution:
public static void stopConnectionProvider() {
final SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) sessionFactory;
ConnectionProvider connectionProvider = sessionFactoryImplementor.getConnectionProvider();
if (Stoppable.class.isInstance(connectionProvider)) {
((Stoppable) connectionProvider).stop();
}
}
This works, but it's ugly, hacky, uses a deprecated method, etc. The better solution would be to just use a "real" connection pool, like c3p0, which can be enabled just by adding the following properties to your hibernate.cfg.xml:
<property name="hibernate.c3p0.acquire_increment">1</property>
<property name="hibernate.c3p0.idle_test_period">100</property>
<property name="hibernate.c3p0.max_size">10</property>
<property name="hibernate.c3p0.max_statements">10</property>
<property name="hibernate.c3p0.min_size">10</property>
<property name="hibernate.c3p0.timeout">100</property>
Note that if you use another connection pool, you should remove this connection pool property which is currently in your config:
<!-- JDBC connection pool (use the built-in) -->
<property name="connection.pool_size">1</property>
Edit: to use c3p0 connection pooling you'll also need the hibernate-c3p0 dependency. Maven example for 4.3.0-SNAPSHOT from the Hibernate snapshots repo:
<repositories>
...
<repository>
<id>hibernate-snapshots</id>
<url>http://snapshots.jboss.org/maven2/</url>
</repository>
...
</repositories>
<dependencies>
...
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-c3p0</artifactId>
<version>4.3.0-SNAPSHOT</version>
</dependency>
...
<dependencies>
Problem
I'm upgrading my Hibernate to the latest version. With my old `HibernateUtil.java` I had no problems but when upgrading it, the SessionFactory doesn't seem to close anymore. This is my new `HibernateUtil.java` class: ``` import org.hibernate.HibernateException; import org.hibernate.cfg.Configuration; import org.hibernate.SessionFactory; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { Configuration configuration = new Configuration().configure(); StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().applySettings(configuration.getProperties()); sessionFactory = configuration.buildSessionFactory(builder.build()); } catch (HibernateException ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void closeSessionFactory() { sessionFactory.close(); } } ``` This is my old `HibernateUtil.java` class: ``` import org.hibernate.cfg.Configuration; import org.hibernate.SessionFactory; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { // Create the SessionFactory from standard (hibernate.cfg.xml) // config file. sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Log the exception. System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } public static void closeSessionFactory() { sessionFactory.close(); } } ``` This is my hibernate.cfg.xml: ``` <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="hibernate.dialect">org.hibernate.dialect.H2Dialect</property> <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property> <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/mydatabase</property> <property name="hibernate.connection.username">user</property> <property name="hibernate.connection.password">pass</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect">org.hibernate.dialect.H2Dialect</property> <!-- Disable the second-level cache --> <property name="cache.provider_class">org.hibernate.cache.internal.NoCacheProvider</property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">false</property> <property name="format_sql">false</property> <property name="use_sql_comments">false</property> <!-- Use the thread as the context --> <property name="hibernate.current_session_context_class">thread</property> <!-- Use these files for mapping configuration --> <mapping resource="test/Person.hbm.xml"/> </session-factory> </hibernate-configuration> ``` Code in which I create the session: ``` public class Helper { Session session = null; public Helper() { this.session = HibernateUtil.getSessionFactory().getCurrentSession(); } public List getPeople(int id) { ... } } ``` Main method: ``` public static void main(String args[]) { Logger log = Logger.getLogger("org.hibernate"); log.setLevel(Level.WARNING); Helper helper = new Helper(); List<Person> people = helper.getPeople(1); for (int i = 0; i < people.size(); i++) { System.out.println("people " + i + ": " + people.get(i).getID()); } HibernateUtil.closeSessionFactory(); } ```