【问题标题】:How does getCurrentSession work without openSession?如果没有 openSession,getCurrentSession 是如何工作的?
【发布时间】:2015-08-07 06:39:22
【问题描述】:

这是我的代码:

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">

<hibernate-configuration>
    <session-factory>
        <property name="connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/sakila</property>
        <property name="connection.username">root</property>
        <property name="connection.password"/>

        <property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>

        <property name="current_session_context_class">thread</property>
        <property name="hibernate.show_sql">false</property>

        <mapping class="biz.tugay.saqila.model.Actor" />
    </session-factory>
</hibernate-configuration>

HibernateUtil.java

package biz.tugay.saqila.dao;
/* User: koray@tugay.biz Date: 06/08/15 Time: 18:29 */

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.cfg.Configuration;
import org.hibernate.service.ServiceRegistry;

public class HibernateUtil {

    private static SessionFactory SESSION_FACTORY;

    public static void buildSessionFactory() {
        if (SESSION_FACTORY != null) {
            return;
        }

        Configuration configuration = new Configuration();
        configuration.configure();
        ServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder()
                .applySettings(configuration.getProperties()).build();
        SESSION_FACTORY = configuration.buildSessionFactory(serviceRegistry);

    }

    public static Session getCurrentSession() {
        return SESSION_FACTORY.getCurrentSession();
    }

    public static void killSessionFactory() {
        if (SESSION_FACTORY != null) {
            SESSION_FACTORY.close();
        }
    }

}

还有一个示例 DAO 类:

package biz.tugay.saqila.dao;
/* User: koray@tugay.biz Date: 06/08/15 Time: 18:37 */

import biz.tugay.saqila.model.Actor;
import org.hibernate.Session;

import java.util.List;

@SuppressWarnings("unchecked")
public class ActorDao {

    public List<Actor> getAllActors() {
        Session session = HibernateUtil.getCurrentSession();
        session.beginTransaction();
        List<Actor> actors = session.createQuery("FROM Actor").list();
        session.close();
        return actors;
    }

    public Actor getWithId(int id) {
        Session session = HibernateUtil.getCurrentSession();
        session.beginTransaction();
        Actor actor = (Actor) session.get(Actor.class, id);
        session.close();
        return actor;
    }

}

正如你所见,我没有在任何地方调用 openSession,只是 getCurrentSession。但这是如何工作的?

另外,这是正确的做事方式,还是我很幸运这行得通?

顺便说一句,我也有这个监听器:

package biz.tugay.saqila.servlet;
/* User: koray@tugay.biz Date: 06/08/15 Time: 19:00 */


import biz.tugay.saqila.dao.HibernateUtil;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.servlet.annotation.WebListener;

@WebListener
public class HibernateConfigurator implements ServletContextListener {

    @Override
    public void contextInitialized(ServletContextEvent servletContextEvent) {
        HibernateUtil.buildSessionFactory();
    }

    @Override
    public void contextDestroyed(ServletContextEvent servletContextEvent) {
        System.out.println("Killing Session Factory.");
        HibernateUtil.killSessionFactory();
    }

}

【问题讨论】:

    标签: java hibernate servlets


    【解决方案1】:

    如果您将hibernate.current_session_context_class 设置为线程,那么您可以使用SessionFactory.getCurrentSession() 在应用程序中的任何位置访问该会话。

    如果您不希望会话绑定到上下文,请使用 OpenSession 。在某些情况下,您可能需要不同的会话 - 除了绑定到上下文的会话,在这种情况下您可以使用 OpenSession 而不是 currentSession。

    SessionFactory.openSession() 总是打开一个新会话,一旦您完成数据库操作就必须关闭该会话。 SessionFactory.getCurrentSession() 返回一个绑定到上下文的会话,你不需要关闭它。

    您永远不应该为每个应用程序使用一个会话 - 会话不是线程安全的对象,它不能被多个线程共享。始终使用每个应用程序一个会话交易

    【讨论】:

    • 你不应该在每个应用程序中使用一个会话 - 会话不是线程安全对象 -> 所以你的意思是我应该使用 openSession?
    • 7 年的蟋蟀声
    【解决方案2】:

    The javadoc 说:

    获取当前会话。确切的“当前”含义的定义由配置为使用的 CurrentSessionContext impl 控制。

    您正在使用 ThreadLocalSessionContext。 Its javadoc 说:

    一个 CurrentSessionContext impl,它通过当前执行线程来限定当前会话的概念。 [...] 出于可用性考虑,我们决定让这个默认 impl 在第一次请求时实际生成一个会话,然后在与该会话关联的事务提交/回滚后清理它。

    您不应该关闭以这种方式获得的会话。相反,您应该提交已开始的事务。如文档所述,这将关闭会话。

    【讨论】:

    • 那么这是正确的做法吗?会话会话 = HibernateUtil.getCurrentSession();事务事务 = session.beginTransaction(); List actor = session.createQuery("FROM Actor").list();事务.commit();返回演员;
    • 更好,但仍然不能正确处理异常。文档中解释了正确的成语:docs.jboss.org/hibernate/orm/4.3/manual/en-US/html_single/…。但如果我是你,我真的会尝试使用允许声明式事务管理的框架:EJB 或 Spring。这样您就可以避免编写所有这些样板代码。
    猜你喜欢
    • 2011-12-24
    • 2015-11-12
    • 2012-07-06
    • 2016-04-20
    • 2016-12-21
    • 2012-12-10
    • 2014-01-30
    • 1970-01-01
    • 2015-10-23
    相关资源
    最近更新 更多