`
echohfut
  • 浏览: 223988 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

open session in view

阅读更多

摘自:http://community.jboss.org/wiki/OpenSessioninView

 

1. 问题描述

A common issue in a typical (web-)application is the rendering of the view, after the main logic of the action has been completed, and therefore, the Hibernate Session has already been closed and the database transaction has ended. If you access detached objects that have been loaded in the Session inside your JSP (or any other view rendering mechanism), you might hit an unloaded collection or a proxy that isn't initialized. The exception you get is: LazyInitializationException: Session has been closed (or a very similar message).

比如页面是学生信息显示,学生实体对象包含一个课程实体列表,并且采用惰性装载。那么页面显示学生的课程信息时可能Session已关闭,事务已提交,hibernate会抛出上面的异常。

 

基本上问题出现在一次request 与 response 之间layz loading的对象上。open session in view解决方案也是应用在相应的scope内。如果是用JPA,那么对应Session的是EntityManager,相应的是open entity manager in view.

如果渲染发生在servlet中,在servlet中打开和关闭Session(Session per Request"), 这样是没问题的。但如果渲染是用JSP,那么就有这里所说的问题,这时就需要Open Session in View的filter方式。Filter后处理发生在 “渲染JSP模板生成Html” 后, 这时候才关闭Session或者EntityManager

 

2. 解决方案

2.1

为detached objects 重新开一个session

 

2.2 open session in view

in most applications you need the following: when an HTTP request has to be handled, a new Session and database transaction will begin. Right before the response is send to the client, and after all the work has been done, the transaction will be committed, and the Session will be closed. A good standard interceptor in a servlet container is a ServletFilter .

 

 

 

public class HibernateSessionRequestFilter implements Filter {
 
    private static Log log = LogFactory.getLog(HibernateSessionRequestFilter.class);
 
    private SessionFactory sf;
 
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {
 
        try {
            log.debug("Starting a database transaction");
            sf.getCurrentSession().beginTransaction();
 
            // Call the next filter (continue request processing)
            chain.doFilter(request, response);
 
            // Commit and cleanup
            log.debug("Committing the database transaction");
            sf.getCurrentSession().getTransaction().commit();
 
        } catch (StaleObjectStateException staleEx) {
            log.error("This interceptor does not implement optimistic concurrency control!");
            log.error("Your application will not work until you add compensation actions!");
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            ex.printStackTrace();
            try {
                if (sf.getCurrentSession().getTransaction().isActive()) {
                    log.debug("Trying to rollback database transaction after exception");
                    sf.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                log.error("Could not rollback transaction after exception!", rbEx);
            }
 
            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("Initializing filter...");
        log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
        sf = HibernateUtil.getSessionFactory();
    }
 
    public void destroy() {}
 
}

 

    <filter>
        <filter-name>HibernateFilter</filter-name>
        <filter-class>my.package.HibernateSessionRequestFilter</filter-class>
    </filter>

    <filter-mapping>
        <filter-name>HibernateFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

 

public class ItemDAO {
 
    Session currentSession;
 
    public ItemDAO() {
        currentSession = HibernateUtil.getSessionFactory().getCurrentSession();
    }
 
    public Item getItemById(Long itemId) {
        return (Item) currentSession.load(Item.class, itemId);
    }
}

 

public String execute(HttpRequest request) {
 
    Long itemId = request.getParameter(ITEM_ID);
 
    ItemDAO dao = new ItemDAO();
 
    request.setAttribute( RESULT, dao.getItemById(itemId) );
  
    return "success";
}

 

 

3. filter for long conversation 长事务

 

If you'd like to use a single Session for several database transactions, you either have to implement it completely yourself, or you have to use the built-in "application managed" strategy:

 

 

 

To enable the application-managed "current" Session strategy, set your hibernate.current_session_context_class configuration property to org.hibernate.context.ManagedSessionContext (or simply "managed" in Hibernate 3.2). You can now bind and unbind the "current" Session with static methods, and control the FlushMode and flushing manually.

 

public class HibernateSessionConversationFilter
        implements Filter {
 
    private static Log log = LogFactory.getLog(HibernateSessionConversationFilter.class);
 
    private SessionFactory sf;
 
    public static final String HIBERNATE_SESSION_KEY = "hibernateSession";
    public static final String END_OF_CONVERSATION_FLAG = "endOfConversation";
 
    public void doFilter(ServletRequest request,
                         ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException {
 
        org.hibernate.classic.Session currentSession;
 
        // Try to get a Hibernate Session from the HttpSession
        HttpSession httpSession =
                ((HttpServletRequest) request).getSession();
        Session disconnectedSession =
                (Session) httpSession.getAttribute(HIBERNATE_SESSION_KEY);
 
        try {
 
            // Start a new conversation or in the middle?
            if (disconnectedSession == null) {
                log.debug(">>> New conversation");
                currentSession = sf.openSession();
                currentSession.setFlushMode(FlushMode.NEVER);
            } else {
                log.debug("< Continuing conversation");
                currentSession = (org.hibernate.classic.Session) disconnectedSession;
            }
 
            log.debug("Binding the current Session");
            ManagedSessionContext.bind(currentSession);
 
            log.debug("Starting a database transaction");
            currentSession.beginTransaction();
 
            log.debug("Processing the event");
            chain.doFilter(request, response);
 
            log.debug("Unbinding Session after processing");
            currentSession = ManagedSessionContext.unbind(sf);
 
            // End or continue the long-running conversation?
            if (request.getAttribute(END_OF_CONVERSATION_FLAG) != null ||
                request.getParameter(END_OF_CONVERSATION_FLAG) != null) {
 
                log.debug("Flushing Session");
                currentSession.flush();
 
                log.debug("Committing the database transaction");
                currentSession.getTransaction().commit();
 
                log.debug("Closing the Session");
                currentSession.close();
 
                log.debug("Cleaning Session from HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);
 
                log.debug("<<< End of conversation");
 
            } else {
 
                log.debug("Committing database transaction");
                currentSession.getTransaction().commit();
 
                log.debug("Storing Session in the HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, currentSession);
 
                log.debug("> Returning to user in conversation");
            }
 
        } catch (StaleObjectStateException staleEx) {
            log.error("This interceptor does not implement optimistic concurrency control!");
            log.error("Your application will not work until you add compensation actions!");
            // Rollback, close everything, possibly compensate for any permanent changes
            // during the conversation, and finally restart business conversation. Maybe
            // give the user of the application a chance to merge some of his work with
            // fresh data... what you do here depends on your applications design.
            throw staleEx;
        } catch (Throwable ex) {
            // Rollback only
            try {
                if (sf.getCurrentSession().getTransaction().isActive()) {
                    log.debug("Trying to rollback database transaction after exception");
                    sf.getCurrentSession().getTransaction().rollback();
                }
            } catch (Throwable rbEx) {
                log.error("Could not rollback transaction after exception!", rbEx);
            } finally {
                log.error("Cleanup after exception!");
 
                // Cleanup
                log.debug("Unbinding Session after exception");
                currentSession = ManagedSessionContext.unbind(sf);
 
                log.debug("Closing Session after exception");
                currentSession.close();
 
                log.debug("Removing Session from HttpSession");
                httpSession.setAttribute(HIBERNATE_SESSION_KEY, null);
 
            }
 
            // Let others handle it... maybe another interceptor for exceptions?
            throw new ServletException(ex);
        }
 
    }
 
    public void init(FilterConfig filterConfig) throws ServletException {
        log.debug("Initializing filter...");
        log.debug("Obtaining SessionFactory from static HibernateUtil singleton");
        sf = HibernateUtil.getSessionFactory();
    }
 
    public void destroy() {}
 
}

 

分享到:
评论

相关推荐

    Open Session in View模式.PPT

    Open Session in View模式.PPT

    struts2+hibernate3 open session in view

    struts2+hibernate3 做的小项目 使用了struts2插件实现pen session in view

    Open_Session_In_View详解.doc

    在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如 company.getEmployees(),否则Hibernate抛...

    使用Spring引起的错误

    使用Spring提供的Open Session In View而引起Write operations are not allowed in read-only mode (FlushMode.NEVER) 错误解决

    SSH整合 struts+hibernate+spring

    SSH整合概述 应用IoC进行整合 应用AOP进行整合 Open Session In View模式

    Struts Spring Hibernate 整合 OpenSessionInView 例子

    为了练手培训,给大家准备的 Open Session In View 的简单例子,纯代码,大家可以参考,其中主要说了六部分内容: 1.通过接口编程 2.通过spring注入dao到 action 3.通过 open session in view filter 支持 延迟加载...

    spring-jpa-wicket-bootstrap:使用 Spring、JPA、Hibernate、Wicket 和 Bootstrap 的 J2EE Web 模板。 在 Tomcat 和 Postgres DB 上测试

    它演示了MvC 、 SoC 、 IoC 、 DAO 、 Service layer和Open Session in View模式以及其他 J2EE 最佳实践。 该模板可以轻松扩展为功能齐全的基于 Wicket 的 Web 应用程序。 用法 该模板使用 maven 并在 Tomcat7 上...

    Android google io 2012 opensource已通过编译无错误

    View detailed session, code lab, and speaker information, including speaker bios, photos, and Google+ profiles +1 sessions right from the app Participate in public #io12 conversations on Google+ Guide...

    plug-In PHP- 100 Power Solutions

    Open Session; Close Session; Secure Session; Manage Cookie; Block User by Cookie; Create Google Chart; Curl Get Contents; Fetch Wiki Page; Fetch Flickr Stream; Get Yahoo! Answers; Search Yahoo!; Get ...

    JCreatorV4

    You can open multiple files in the Open dialogue box, by holding down the Shift or Ctrl key down as you select each file. You can press ESC to return from Full Screen mode to normal mode.

    UE(官方下载)

    In this tutorial, we'll cover some of the basics of Unicode-encoded text and Unicode files, and how to view and manipulate it in UltraEdit. Search and delete lines found UEStudio and UltraEdit provide...

    PLSQL Developer 8.0.3.1510 中文注册版下载

    * Describe Window now also shows the view comments in the header * Export Tables would change nls_date_format in single session mode and dual session mode * Auto Replace now supports Undo to continue...

    FastReport.v4.15 for.Delphi.BCB.Full.Source企业版含ClientServer中文修正版支持D4-XE5

    - fixed bug with URLs in Open Document Text and Open Document Spreadsheet exports - fixed format string in XLS OLE export - fixed format string in XLS BIFF8 export - fixed output of the check boxes ...

    servlet2.4doc

    Encodes the specified URL by including the session ID in it, or, if encoding is not needed, returns the URL unchanged. -------------------------------------------------------------------------------...

    Bloodshed Dev-C++

    * Multi-select files in project-view (when "double-click to open" is configured in Environment Settings) * Resource files are treated as ordinary files now * Updates in "Project Options/Files" code * ...

    MobaXterm 10.8最新professional版专业版

    更新的内容包含: Version 10.8 (2018-07-07) Bugfix: fixed the error message which occured when running the graphical package manager...引用地址:http://www.open-open.com/lib/view/open1437704662490.html

    BCGControlBarPro.v12.00

    It is stored in CBCGPGridCtrl::m_PrintParams::m_pageInfo member and in CPrintInfo::m_lpUserData member of the CPrintInfo object used while printing at the current print session. Added an option to ...

    Sublime Text Build 3124 x64 Setup.exe

    File encoding of open files is now stored in the session Build Systems may define a cancel command using the "cancel" key Syntax: Added clear_scopes directive, to give more control over the generated ...

    PLSQL.Developer v11.0.0.1762 主程序+ v10中文包+keygen

    Triggers can now be created in the context of a table or view Folders added for Primary, Unique and Foreign key constraints for views Search Bar enhancements A new Search in files option allows you ...

    CE中文版-启点CE过NP中文.exe

    Added a statusbar to the hexview in memoryview Pointerscan for value scans now add the results to the overflow queue Opening a file and changing bytes do not change them to the file anymore (you need ...

Global site tag (gtag.js) - Google Analytics