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

时间:2014-05-14 05:35:40

标签: java hibernate configuration transactions c3p0

我最近将我的Hibernate版本升级到4.3.4.Final。 Based on Contextual Sessions configuration of Hibernate this new version is not based on ThreadLocal anymore.如果到目前为止我所得到的是正确的,我是否需要做任何事情来提高效率?如果不正确我该怎么办?我不知道。

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

hibernate.cfg.xml中

<hibernate-configuration>

    <session-factory>

    <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
    <property name="hibernate.connection.url">jdbc:mysql://localhost/myDB</property>
    <property name="hibernate.connection.username">root</property>
    <property name="hibernate.connection.password"></property>
    <property name="hibernate.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>

    <property name="show_sql">true</property>

    <property name="hibernate.c3p0.min_size">5</property>
    <property name="hibernate.c3p0.max_size">20</property>
    <property name="hibernate.c3p0.timeout">300</property>
    <property name="hibernate.c3p0.max_statements">50</property>
    <property name="hibernate.c3p0.idle_test_period">3000</property>
        <!--        <property name="hbm2ddl.auto">update</property>-->

        <mapping class="com.myProject.entities.users" />
        ...

当前配置和代码

基于答案吹响和this part of documentation 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<Session> 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;

2 个答案:

答案 0 :(得分:3)

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

除了您应该依赖Hibernate 4 bootstrap机制这一事实外,您的代码还存在以下问题:

  1. 会话工厂重建未同步

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

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

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

    interface SessionCallback<T> {T doInSession(Session session);}
    
    class HibernateUtil {
    
        public T execute(SessionCallback<T> 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<Void>() {
        public Void doInSession(Session session) {
            session.createQuery(...);
            return null;
        }
    });
    
    final customerID = ...
    
    Customer customer = HibernateUtil.execute(new SessionCallback<Customer>() {
        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。

答案 1 :(得分:2)

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

以下信息全部(可用)来自Hibernate 4.3手册章节2.2. Contextual sessions13. Transactions and Concurrency

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

如果没有&#34;工作单位&#34;但只是一堆(捆绑的)查询和更新,只需遵循non-managed environment的第一个习语(来自前面提到的第13章)。除非你能证明这会带来性能问题(*),否则不要尝试进行优化,因为那是root of all evil

如果有&#34;工作单位&#34;或者&#34;每次请求会话&#34;,问题中的HibernateUtil可以使用org.hibernate.context.internal.ThreadLocalSessionContext替换为CurrentSessionContext(参见前面提到的第2.2章)并在第二个之后non-managed environment的成语。

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

注意讨论&#34;工作单元的章节&#34;:一个好的软件架构取决于对商业交易&#34;和#34;申请交易&#34;适用于您的申请。

(*)性能问题可能由配置问题引起,例如: this question在Hibernate手册中有相关文档here