如何在Hibernate 4.3.4.Final中配置和获取会话?

我最近将我的Hibernate版本升级到4.3.4.Final。 基于Hibernate的Contextual Sessions配置,这个新版本不再基于ThreadLocal。 如果我到目前为止所做的是正确的,我是否需要做任何事情来提高效率? 如果不正确我该怎么办? 我没有线索。

请注意 ,文档中提到:Hibernate提供了三种当前会话跟踪方法。 基于“线程”的方法不适用于生产用途; 它仅适用于原型设计和教程,例如本教程。

的hibernate.cfg.xml

  com.mysql.jdbc.Driver jdbc:mysql://localhost/myDB root  org.hibernate.dialect.MySQLDialect  thread  org.hibernate.cache.NoCacheProvider true 5 20 300 50 3000 <!-- update-->  ... 

当前配置和代码

基于答案吹响和这部分文档 mu当前配置如下:

  public class HibernateUtil { private static SessionFactory sessionFactory = buildSessionFactory(); private static SessionFactory buildSessionFactory() { try { Configuration configuration = new Configuration(); return configuration.configure() .buildSessionFactory( new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()) .build()); } catch (Throwable ex) { System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } } 

代码如下

  final Session session = HibernateUtil.getSessionFactory().openSession(); try { final Transaction tx = session.beginTransaction(); try { ... 

以前的配置和代码

 public class HibernateUtil { private static ServiceRegistry serviceRegistry; private static final ThreadLocal threadLocal = new ThreadLocal(); private static SessionFactory sessionFactory; private static SessionFactory configureSessionFactory() { try { Configuration configuration = new Configuration(); configuration.configure(); serviceRegistry = new StandardServiceRegistryBuilder() .applySettings(configuration.getProperties()) .build(); sessionFactory = configuration.buildSessionFactory(serviceRegistry); return sessionFactory; } catch (HibernateException e) { System.out.append("** Exception in SessionFactory **"); e.printStackTrace(); } return sessionFactory; } static { try { sessionFactory = configureSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } private HibernateUtil() { } public static SessionFactory getSessionFactory() { return sessionFactory; } public static Session getSession() throws HibernateException { Session session = threadLocal.get(); if (session == null || !session.isOpen()) { if (sessionFactory == null) { rebuildSessionFactory(); } session = (sessionFactory != null) ? sessionFactory.openSession() : null; threadLocal.set(session); } return session; } public static void rebuildSessionFactory() { try { sessionFactory = configureSessionFactory(); } catch (Exception e) { System.err.println("%%%% Error Creating SessionFactory %%%%"); e.printStackTrace(); } } public static void closeSession() throws HibernateException { Session session = (Session) threadLocal.get(); threadLocal.set(null); if (session != null) { if (session.isOpen()) { session.close(); } } } } 

用于访问事务和提交命令的代码

  final Session session = HibernateUtil.getSession(); try { final Transaction tx = session.beginTransaction(); try { //Commands related to query go here if (!tx.wasCommitted()) { tx.commit(); } if (session.isOpen()) { session.close(); } return true; } catch (Exception e) { tx.rollback(); return false; } } finally { HibernateUtil.closeSession(); } return false; 

我会删除TreadUtil类,它让我想起Spring 1.0 Hibernate集成风格。 如果你打算转移到Hibernate 4。

除了您应该依赖Hibernate 4 引导机制之外,您的代码还存在以下问题:

  1. 会话工厂重建不同步

      synchronized(HibernateUtil.class) { if (sessionFactory == null) { rebuildSessionFactory(); } } 
  2. 我不明白为什么你需要重建它,因为你从未将它设置为null,会话工厂被初始化为静态块。

如果你总是需要在HibernateUtil.openSession()try / finally块中包装Hibernate代码,那么在将业务逻辑与事务逻辑混合时,你会复制很多会话管理逻辑。 这违反了单一责任原则。

如果您仍然不想让HibernateUtil运行,您至少可以使用类似于JDBCTemplate的机制来抽象模板方法中的会话/事务管理,同时在Callable中提供业务代码,这可能看起来像:

 interface SessionCallback {T doInSession(Session session);} class HibernateUtil { public T execute(SessionCallback action) { try{ //open session //open transcation T result = action.doInSession(sessionFactory.getCurrentSession()); //commit tx return result; } catch(RuntimeException e) { //rollback tx throw e; } finally { //close session } } } HibernateUtil.execute(new SessionCallback() { public Void doInSession(Session session) { session.createQuery(...); return null; } }); final customerID = ... Customer customer = HibernateUtil.execute(new SessionCallback() { public Customer doInSession(Session session) { return (Customer) session.get(Customer.class, customerID); return null; } }); 

查看代码表明您希望JDBC资源本地事务具有每个请求的会话访问惯用语,这意味着您需要ThreadLocalSessionContext:

 hibernate.current_session_context_class=thread hibernate.transaction.factory_class=JDBCTransactionFactory 

额外

您可以考虑切换到JPA并将Hibernate属性移动到persistence.xml。

只需访问应用程序中的单个SessionFactory实例即可。

以下信息全部(可用)来自Hibernate 4.3手册第2.2章。 上下文会话和13.事务和并发 。

SessionFactory是一个昂贵的创建线程安全对象,旨在由所有应用程序线程共享。它通常在应用程序启动时从Configuration实例创建一次。”
会话是一种廉价的,非线程安全的对象,应该使用一次,然后丢弃,用于:单个请求,对话或单个工作单元。”

如果没有“工作单元”而只是一堆(捆绑的)查询和更新,只需按照非托管环境的第一个习语(来自前面提到的第13章)。 除非你能certificate这会带来性能问题(*),否则不要试图优化,因为这是所有邪恶的根源 。

如果存在“工作单元”或“每个请求会话”,则可以使用org.hibernate.context.internal.ThreadLocalSessionContext作为CurrentSessionContext (参见前面提到的第2.2章)并在第二个之后替换问题中的HibernateUtil 。 非托管环境的习语。

如果使用JTA,请将ThreadLocalSessionContext替换为org.hibernate.context.internal.JTASessionContext并按照使用JTA中描述的惯用法进行操作。

请注意讨论“工作单元”的章节:软件的良好架构取决于对“业务事务”和“应用程序事务”对您的应用程序意味着什么的良好理解。

(*)性能问题可能是由配置问题引起的,例如这个问题在Hibernate手册中有相关文档。