zoukankan      html  css  js  c++  java
  • Web项目中定时任务无法绑定SessionFactory的问题解决

    正常我们在web开发中,由于需要在页面上或者脱离事务时使用到懒加载对应的对象,一般都采用Open Session In View模式。
     

    Open Session In View

     
    OpenSessionInView 模式用法探讨,在没有使用Spring提供的Open Session In View情况下,因需要在service(or Dao)层里把session关闭,所以lazy loading 为true的话,要在应用层内把关系集合都初始化,如company.getEmployees(),否则Hibernate抛session already closed Exception。 
     
    Open Session In View提供了一种简便的方法,较好地解决了lazy loading问题。它有两种配置方式OpenSessionInViewInterceptor和OpenSessionInViewFilter(具体参看SpringSide),功能相同,只是一个在web.xml配置,另一个在application.xml配置而已。 
     
    Open Session In View在request把session绑定到当前thread期间一直保持hibernate session在open状态,使session在request的整个期间都可以使用,如在View层里PO也可以lazy loading数据,如 ${ company.employees }。当View 层逻辑完成后,才会通过Filter的doFilter方法或Interceptor的postHandle方法自动关闭session。
     
    Hibernate中自带了OpenSessionInViewFilter,我们可以直接在web.xml中对其进行配置:
    <filter>
            <filter-name>openSessionInViewFilter</filter-name>
            <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
            <init-param>
                <param-name>singleSession</param-name>
                <param-value>true</param-value>
            </init-param>
        </filter>
    <filter-mapping>
            <filter-name>openSessionInViewFilter</filter-name>
            <url-pattern>*.do</url-pattern>
        </filter-mapping>
     
     
     
    这样就可以对所有的服务请求都进行过滤,并在其中绑定了SessionFactory,具体可以查看org.springframework.orm.hibernate4.support.OpenSessionInViewFilter源码。
     
    由于定时任务(Cron)并不是通过请求过来的,不会走到Filter中,所以也不会在线程上下文中绑定sessionFactory,因此需要用其他的方式。如果使用OpenSessionInViewInterceptor绑定service,就会将所有的service再次重新绑定,也没有这个必要。
     
    因此,这里我们仿照OpenSessionInViewInterceptor写了一个专门绑定到指定包的Interceptor来做这件事情,确定所有的cron服务都经过sessionFactory绑定即可。
     
    @Component
    @Aspect
    public class OpenSessionInCronInterceptor {
    
        private static final Logger logger = Logger.getLogger(OpenSessionInCronInterceptor.class.getName());
    
        @Autowired
        private SessionFactory sessionFactory;
    
        @Pointcut("execution(void com.ejiapei.service.cron.*.work())")
        protected void definePointcut() {
        }
    
        @Before("definePointcut()")
        public void preHandle() throws DataAccessException {
            logger.info("Opening Hibernate Session in OpenSessionInViewInterceptor");
            Session session = openSession();
            TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(session));
        }
    
        /**
         * Unbind the Hibernate <code>Session</code> from the thread and close it).
         *
         * @see org.springframework.transaction.support.TransactionSynchronizationManager
         */
        @After("definePointcut()")
        public void afterCompletion() throws DataAccessException {
            SessionHolder sessionHolder =
                    (SessionHolder) TransactionSynchronizationManager.unbindResource(sessionFactory);
            logger.info("Closing Hibernate Session in OpenSessionInViewInterceptor");
            SessionFactoryUtils.closeSession(sessionHolder.getSession());
        }
    
        /**
         * Open a Session for the SessionFactory that this interceptor uses.
         * <p>The default implementation delegates to the
         * <code>SessionFactory.openSession</code> method and
         * sets the <code>Session</code>'s flush mode to "MANUAL".
         *
         * @return the Session to use
         * @throws org.springframework.dao.DataAccessResourceFailureException if the Session could not be created
         * @see org.hibernate.FlushMode#MANUAL
         */
        protected Session openSession() throws DataAccessResourceFailureException {
            try {
                Session session = SessionFactoryUtils.openSession(sessionFactory);
                session.setFlushMode(FlushMode.MANUAL);
                return session;
            } catch (HibernateException ex) {
                throw new DataAccessResourceFailureException("Could not open Hibernate Session", ex);
            }
        }
    
    }
     
    首先,我们需要使用@Autowird从当前的Spring容器中获取到绑定的SessionFactory,用来创建Session,这部分与OpenSessionInView Filter/Interceptor的代码比较类似,只不过spring提供的这两个方式做的事情实际上比我们这里需要的还要多。
     
    这样,我们就可以在开始执行定时任务之前使用绑定的SessionFactory去重新开启一个Session,并绑定至SessionHolder,也就是该线程上线文中,就避免了懒加载的问题。 
     
    除此之外,还有一种比较暴力的方式,就是把所有懒加载的地方都修改成Lazy.EAGER,如果这样就改为非懒加载,但是可能会影响性能,因为影响了Hibernate访问数据库的方式。
     
     
     
     
     
  • 相关阅读:
    angular2
    angular1
    JavaScript随笔1
    鼠标样式
    清除浮动
    css-父标签中的子标签默认位置
    [Leetcode] Decode Ways
    [Java] 利用LinkedHashMap来实现LRU Cache
    LinkedHashMap和HashMap的比较使用(转)
    [Java] java.util.Arrays 中使用的 sort 采用的算法 (转)
  • 原文地址:https://www.cnblogs.com/mmaa/p/5789879.html
Copyright © 2011-2022 走看看