我正在将Hibernate升级到最新版本。我的年纪HibernateUtil.java不大,但是升级时,SessionFactory似乎不再关闭。
HibernateUtil.java
这是我的 新 HibernateUtil.java类:
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(); } }
这是我的 老 HibernateUtil.java班级:
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(); } }
这是我的 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>
我在其中创建会话的代码:
public class Helper { Session session = null; public Helper() { this.session = HibernateUtil.getSessionFactory().getCurrentSession(); } public List getPeople(int id) { ... } }
主要方法:
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(); }
没错,Hibernate 4.3.x中似乎存在一个错误,该错误中,由Hibernate的默认连接池生成的线程在关闭时不会被清除。我在这里提交了一个错误(请投票!):
https://hibernate.atlassian.net/browse/HHH-8896
在修复之前,您有两种选择。您可以在HibernateUtil中添加一个方法,并使用它来强制连接池在应用执行结束时自行清理:
public static void stopConnectionProvider() { final SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) sessionFactory; ConnectionProvider connectionProvider = sessionFactoryImplementor.getConnectionProvider(); if (Stoppable.class.isInstance(connectionProvider)) { ((Stoppable) connectionProvider).stop(); } }
这可以工作,但是很丑陋,很笨拙,使用了不推荐使用的方法,等等。更好的解决方案是只使用“真实的”连接池,例如c3p0,只需将以下属性添加到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>
请注意,如果您使用其他连接池,则应删除当前配置中的该连接池属性:
<!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property>
编辑:要使用c3p0连接池,您还需要hibernate-c3p0依赖项。Hibernate快照存储库中的4.3.0-SNAPSHOT的Maven示例:
<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>