如何从 DAO 中的 ServletContext 获取 SessionFactory

Posted

技术标签:

【中文标题】如何从 DAO 中的 ServletContext 获取 SessionFactory【英文标题】:How would I obtain SessionFactory from the ServletContext in the DAO 【发布时间】:2015-12-22 21:32:43 【问题描述】:

我创建了一个这样的 DAO:它基于:Hibernate: CRUD Generic DAO

public class Dao
    SessionFactory sessionFactory;
    // initialise session factory
    public User save(User o)
        return (User) sessionFactory.getCurrentSession().save(o);
    

    public User get(Long id)
        return (User) sessionFactory.getCurrentSession().get(User.class, id);
    

    public User void saveOrUpdate(User o)
                    sessionFactory.getCurrentSession().saveOrUpdate(o);
    

现在,如果我的 sessionFactory 在 DAO 或其他类中,这一切都很好。但我的问题是从 servletContextListener 调用 SessionFactory:这是我在监听器中的代码:

public void contextInitialized(ServletContextEvent event)  
    StandardServiceRegistry registry = new StandardServiceRegistryBuilder().configure().build();
    try 
        sessionFactory = new MetadataSources(registry).buildMetadata().buildSessionFactory();
        event.getServletContext().setAttribute("factory", sessionFactory);
     catch(Exception e) 
        e.printStackTrace();
        StandardServiceRegistryBuilder.destroy( registry );
    

在这种情况下,除了在 DAO 中实际包装 servletRequest 之外,我如何从 DAO 调用 SessionFactory?

【问题讨论】:

为什么要将 Hibernate SessionFactory 存储在 ServletContext 中?关于关注点分离的整个想法是,您不希望您的 MVC 应用程序层必须知道如何访问您的数据,即它不应该从不担心数据/persistence 层完全。你正在做的事情使你的 DAO 完全依赖于你的 web 层,这根本不推荐。 看起来是 XY 问题。您当然不想将 SessionFactory 放在 ServletContext 中并让 DAO 从那里获取它。您应该提供有关应用程序总体设计的一些背景信息。 @Buhake Sindi “为什么要将 Hibernate SessionFactory 存储在 ServletContext 中?” - 我希望它在应用程序启动期间被初始化。我想不出任何其他方式来实现它。 @Serge Ballesta - 这只是一些 CRUD,实用方法很少。 我宁愿 DAO 与 Session 一起工作。如果 DAO 没有会话,则从 SessionFactory 获取它,因为 'sessionFactory' 是每个应用程序生命周期构建一次的线程安全对象。你不必担心它。或者,创建一个单独的 HibernateUtils 类,它会返回一个 SessionFactory 【参考方案1】:

我强烈不鼓励将 Hibernate SessionFactory 存储到 Servlet 的 ServletContext 中。另外,让您的 DAO 使用您的 Hibernate Session

为了解决您的 Hibernate SessionFactory 实例化一次的问题,我创建了一个单例类来管理它:

/**
 * 
 */
package za.co.sindi.persistence.util;

import java.util.logging.Level;
import java.util.logging.Logger;

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

/**
 * This is a Hibernate utility class that strictly uses the Hibernate 4.x library.
 * 
 * @author Buhake Sindi
 * @since 26 November 2012
 *
 */
public final class HibernateUtils 

    private static final Logger logger = Logger.getLogger(HibernateUtils.class.getName());
    private static Configuration configuration;
    private static SessionFactory sessionFactory;
    private static ServiceRegistry serviceRegistry;
    private static final ThreadLocal<Session> sessionThread = new ThreadLocal<Session>();
    private static final ThreadLocal<Interceptor> interceptorThread = new ThreadLocal<Interceptor>();

    static 
        try 
            configuration = new Configuration();
            serviceRegistry = new StandardServiceRegistryBuilder().build();
            sessionFactory = configuration.configure().buildSessionFactory(serviceRegistry);
         catch (HibernateException e) 
            logger.log(Level.SEVERE, "Error intializing SessionFactory.", e.getLocalizedMessage());
            throw new ExceptionInInitializerError(e);
        
    

    /**
     * Private constructor
     */
    private HibernateUtils() 

    /**
     * @return the sessionFactory
     */
    public static SessionFactory getSessionFactory() 
        return sessionFactory;
    

    /**
     * Retrieves the current session local to the thread.
     * 
     * @return Hibernate @link Session for current thread.
     * @throws HibernateException when Hibernate has a problem opening a new session.
     */
    public static Session getSession() 
        Session session = sessionThread.get();
        if (session == null) 
            Interceptor interceptor = getInterceptor();
            if (interceptor != null) 
                session = getSessionFactory().withOptions().interceptor(interceptor).openSession();
             else 
                session = getSessionFactory().openSession();
            

            if (session != null) 
                sessionThread.set(session);
            
        

        return session;
    

    /**
     * Closes the Hibernate Session (created from the <code>getSession()</code> session.
     */
    public static void closeSession() 
        Session session = sessionThread.get();
        sessionThread.set(null);
        if (session != null && session.isOpen()) 
            session.close();
        
    

    /**
     * Registers a Hibernate @link Interceptor.
     * @param interceptor
     */
    public static void registerInterceptor(Interceptor interceptor) 
        interceptorThread.set(interceptor);
    

    /**
     * Get the registered Hibernate Interceptor.
     * @return
     */
    public static Interceptor getInterceptor() 
        return interceptorThread.get();
    

在我的 DAO 中,我只是将会话检索为 HibernateUtils.getSession();。 这样,我的 MVC 应用程序就不会引用我的特定 DAO 实现。

我希望这会有所帮助。

【讨论】:

我应该在哪里实例化它? 它在static 块中实例化并实例化一次.. 您所要做的就是检索Session。无需担心再次实例化 SessionFactory,因此它是单例类。 您好,您能解释一下为什么不鼓励将 SessionFactory 存储在 ServletContext 中吗?接缝比静态变量更安全。 @Orden 因为ServletContext 是您的前端应用程序,并且您希望分离您的关注点,即您的表示层必须永远不知道存储库层的复杂性。

以上是关于如何从 DAO 中的 ServletContext 获取 SessionFactory的主要内容,如果未能解决你的问题,请参考以下文章

如何从 JAX-WS Web 服务中访问 ServletContext?

如何在 Spring MVC 中的不同类中创建动态 bean

我如何使用从表单中获得的值作为我的 dao 类中的变量?

如何解决 BeanDefinitionStoreException:IOException 从 ServletContext 资源 [/WEB-INF/dispatcher-servlet.xml]

如何防范 DAO 中的治理攻击?

如何使用与 sql server 的 DAO 连接更新 VB6 中的记录集