【问题标题】:Singleton DAO instance keeps old closed session between HTTP transactionsSingleton DAO 实例在 HTTP 事务之间保持旧的关闭会话
【发布时间】:2017-02-15 17:58:00
【问题描述】:

我正在尝试使用 Hibernate 实现“每个 http 请求一个会话”模式,它适用于第一个请求:servlet 的 doGet() 方法打开会话,获取一些内容,然后关闭会话。

但是当我刷新浏览器时,我的 DAO Singleton 实例(其构造函数从 SessionFactory 获取会话)被第二次调用,但仍然使用旧的会话对象(不再调用单例构造函数)。然后我得到一个“会话已关闭”错误。

我猜单例实例必须在 HTTP 请求之间保存在缓存中,所以:我怎样才能再次调用 DAO 单例构造函数? (或者另一个优雅的解决方案来拥有新的 SessionFactory 会话对象?)

非常感谢

小服务程序:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    try {
        // Gets the session, eventually creates one
        Session s = HibernateUtil.currentSession();

        // Gets data from singleton DAO instance
        MySingletonDAO o = MySingletonDAO.getInstance();
        List<Stuff> stuff = o.getAllTheStuff();

        // send it to the view
        request.setAttribute("foo",stuff);
        RequestDispatcher dispatcher = getServletContext().getRequestDispatcher(vue);
        dispatcher.forward(request, response);

    }
             /*  error handling blah blah */
    finally {
        // closing the session
        HibernateUtil.closeSession();
    }

MySingletonDAO.java :

public class MySingletonDAO {
    // Usual singleton syntax
    private static MySingletonDAO INSTANCE = new MySingletonDAO();
    public static MySingletonDAO getInstance() { return INSTANCE;}

    private Session session;

    private MySingletonDAO() {
        session = HibernateUtil.currentSession();
        System.out.println("This constructor is called only on the first HTTP transaction");
    }

    public List<Stuff> getAllTheStuff() {
        try {
            session.beginTransaction();
            Query q = session.createQuery("FROM StuffDBTable");
            session.getTransaction().commit();
            return (List<Stuff>) q.list();
        }
    }
}

一个经典的线程安全 HibernateUtil.java :

public class HibernateUtil {

    private static final SessionFactory sessionFactory;
    public static final ThreadLocal session = new ThreadLocal();

    static {
        try {
            // Creates the SessionFactory
            sessionFactory = new Configuration().configure().buildSessionFactory();
        } catch (HibernateException he) {
            throw new RuntimeException("Conf problem : "+ he.getMessage(), he);
        }
    }


    public static Session currentSession() throws HibernateException {
        Session s = (Session) session.get();
        // Opens a new Session, if this Thread has none
        if (s == null || !s.isOpen() ) {
            s = sessionFactory.openSession();
            session.set(s);
        }
        return s;
    }

    public static void closeSession() throws HibernateException {
        Session s = (Session) session.get();
        session.set(null);
        if (s != null)
            s.close();
    }
}

【问题讨论】:

    标签: java hibernate singleton dao


    【解决方案1】:

    您所要求的没有意义:如果在每次请求时调用单例的构造函数,它就不再是单例了。会话确实在请求结束时关闭,但 DAO 保留对会话的引用,而不是每次调用时都从您的 util 类中获取它。

    你的 DAO 代码应该是

    public class MySingletonDAO {
        private static MySingletonDAO INSTANCE = new MySingletonDAO();
        public static MySingletonDAO getInstance() { return INSTANCE;}
    
        private MySingletonDAO() {
        }
    
        public List<Stuff> getAllTheStuff() {
            Session session = HibernateUtil.currentSession();
            try {
                session.beginTransaction();
                Query q = session.createQuery("FROM StuffDBTable");
                session.getTransaction().commit();
                return (List<Stuff>) q.list();
            }
        }
    }
    

    也就是说,事务应该以声明方式处理,并且应该在服务层而不是 DAO 层处理:事务通常使用不同的 DAO,DAO 返回的实体应该保持管理状态,并且所有的访问和修改都应该进行应该在事务内部对这些实体进行。

    我强烈建议使用 Java EE 容器或 Spring 来为您处理事务和会话处理。您还应该使用标准 JPA API 而不是专有的 Hibernate API。

    【讨论】:

    • 服务层是我需要的线索,我不明白为什么模型必须管理事务和会话。如果我正确地获得了您的有用指导(经过一些浏览),它将充当 Servlet 和 DAO 方法之间的中间层,以管理事务、错误和返回对象处理等次要问题。如果可以的话,对于未来的读者,建议这个链接帮助我了解全局:msdn.microsoft.com/en-us/library/ee658090.aspx
    猜你喜欢
    • 1970-01-01
    • 2015-02-18
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2014-09-24
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多