`
echohfut
  • 浏览: 231203 次
  • 性别: 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 (OSIV) 模式是一种在基于Hibernate的Web应用程序中处理持久化数据的策略,它允许在视图层(例如JSP页面)中安全地访问延迟加载的对象,而无需担心Session已关闭的问题。以下是关于这个模式及其...

    struts2+hibernate3 open session in view

    在这个小项目中,"Open Session in View"(OSIV)模式被采用,这是一种处理持久化数据的策略,以避免在Web应用中出现常见的并发问题,如数据不一致和懒加载异常。 Struts2是一个强大的MVC框架,它提供了一种灵活的...

    Open_Session_In_View详解.doc

    ### Open_Session_In_View详解 #### 一、背景与概念 在使用Hibernate进行对象持久化时,经常遇到的一个问题是关于懒加载(lazy loading)的处理。懒加载是一种优化技术,允许在真正需要某个关联对象的数据时才加载...

    使用Spring引起的错误

    当使用Open Session In View模式时,如果Session的Flush Mode被设置为NEVER,并且尝试执行写操作(如更新或删除),就会触发“Write operations are not allowed in read-only mode (FlushMode.NEVER)”这个异常。...

    Hibernate Session释放模式

    3. **Open Session in View(OSIV)模式** OSIV模式旨在解决Web应用中,由于用户请求可能会引发多次数据库操作,而这些操作可能跨多个HTTP请求。在这种模式下,Session在整个HTTP请求周期内保持打开状态,直到请求...

    hibernate中session的管理

    3. **Open Session in View (OSIV)**:在视图渲染阶段保持Session打开,以允许最后时刻的懒加载,但需要注意防止Session泄露。 总的来说,Hibernate中Session的管理是保证多线程环境下数据一致性的重要环节。...

    spring中lazy=“true”的正常读取关联表(用opensessioninview)

    为了解决这个问题,Spring提供了一个过滤器 `OpenSessionInViewFilter` 或者 `OpenSessionInViewInterceptor`,通常简称为OSIV(Open Session In View)模式。 OSIV模式的核心思想是在Controller层和View层之间保持...

    Hibernate事务管理.

    在没有Spring提供的Open Session In View(OSIV)模式下,事务处理和懒加载(lazy loading)可能会遇到挑战。 懒加载是一种优化策略,允许关联对象在需要时才从数据库加载,而不是在初始加载实体时就全部加载。这...

    Spring延迟加载和声明式事务处理最终解决方案(修正版)

    1. **Open Session in View Interceptor (OSIV)**:这是Spring MVC中的一个拦截器,它的作用是在整个视图渲染过程中保持Hibernate Session的开放,确保在需要的时候可以进行延迟加载。配置OSIV拦截器后,如在`spring...

    ssh中getCurrentSession的使用

    - 首先,需要配置Hibernate,让其知道如何初始化SessionFactory,并启用Open Session In View模式。 - 在业务逻辑代码中,通过SessionFactory实例调用`getCurrentSession()`,然后执行数据库操作。 - 为了处理...

    集成spring的hibernate懒加载

    在Spring整合Hibernate的情况下,Session通常通过Transaction Management进行管理,比如使用`Open Session in View`(OSIV)模式或者基于注解的事务管理。 当你尝试在Controller层或者视图层访问懒加载的属性时,...

    课程hibernate的事务和并发.pdf

    这种方式被称为ThreadLocal Session和Open Session in View模式,能够简化事务和Session的生命周期管理。 在实际应用中,需要确保正确地开启和结束Session及事务,并将其与数据访问操作结合。HibernateUtil类可以...

    ssh_inte2模板常用方法&延迟加载问题

    可以考虑将事务范围扩大,或者使用开放Session视图模式(Open Session In View,OSIV),让Session贯穿整个HTTP请求,但请注意,OSIV模式可能导致更多的并发问题,需要谨慎使用。 3. **使用Eager Loading**:如果...

    SpringBoot-SpringData-懒加载

    2. **启用Hibernate的开放 session in view**:在Spring Boot中,如果使用Hibernate作为JPA的实现,需要在配置文件(application.properties或application.yml)中开启Open Session In View(OSIV)过滤器,以解决懒...

    hibernate笔记

    Open Session in View(OSIV)模式是一种常见的Hibernate优化模式,主要用于提高读取操作的性能。在这种模式下,Session在整个HTTP请求周期内保持打开状态。 ##### OSIV 实现方式 - **Servlet Filter 方式**:最常见...

    SSH错误集中分析.

    确保在需要的地方启用Open Session in View或者在查询时一次性加载关联数据。 2. **SQL异常**:错误的HQL或Criteria查询可能导致SQL语法错误,检查并修正查询语句。 四、Spring的常见错误 1. **AOP配置**:如果...

    hibernate的lazy策略forClass

    2. 使用Open Session In View模式,将Session的生命周期扩展到整个HTTP请求,但此方法可能带来事务管理和性能问题。 3. 在需要访问懒加载属性时,确保在Session内进行操作,或者使用`Hibernate.initialize()`手动...

    【北大青鸟内部教程】jsp中关于Hibernate延时加载的问题

    为解决此问题,可以在Controller层或Service层提前加载关联数据,或者使用Hibernate的“开放Session视图”(Open Session in View)模式。 3. **事务管理**:延时加载需要在一个有效的Hibernate Session内进行。在...

    SSH常用面试题

    #### 十、Hibernate中的Open Session in View模式 1. **模式介绍:**Open Session in View模式是一种使用Hibernate时的高级技术,它通过在每个HTTP请求开始时打开一个Session,在请求结束时关闭这个Session,从而...

    一次hibernate的优化实践

    - 使用Open Session in View模式需谨慎,因为它可能导致事务边界不清,影响性能。 4. **实体设计与映射优化** - 调整懒加载(Lazy Loading)和急加载(Eager Loading)策略,避免因延迟加载引发的额外查询。 - ...

Global site tag (gtag.js) - Google Analytics