`
brandNewUser
  • 浏览: 453103 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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访问数据库的方式。
 
 
 
 
 
分享到:
评论

相关推荐

    ssh2+quartz整合

    通过分析和运行这些文件,开发者可以深入理解如何在实际项目中实现SSH2与Quartz的整合,以及如何定义和管理定时任务。这有助于提升对Java Web开发和任务调度的理解,为构建复杂的企业级应用打下坚实基础。

    struts,spring,hibernate整合

    此外,Spring还能帮助整合其他服务,如邮件、定时任务等。 具体整合步骤通常包括以下几点: 1. **配置Struts**:在struts-config.xml中配置Action和ActionForm,同时引入Spring的控制器代理,将Action的实例化交给...

    图书管理系统(struts+hibernate+spring).zip.zip

    总之,这个“图书管理系统(struts+hibernate+spring).zip”项目是一个典型的Java Web应用实例,它充分展示了Struts、Hibernate和Spring在实际开发中的应用,对于学习和理解这些框架有着极大的帮助。开发者可以通过...

    《精通Spring 2.x-企业应用开发详解》18-19

    5. **Spring的批量处理与定时任务**:Spring Batch提供了批处理操作的支持,而Spring Task则用于调度定时任务。这两个模块可以帮助开发者构建高效、可扩展的企业级后台处理系统。 通过对这两章内容的学习,读者能够...

    Spring-Reference_zh_CN(Spring中文参考手册)

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1. 简介 ...

    Spring中文帮助文档

    9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...

    Spring 2.0 开发参考手册

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    spring chm文档

    9.9. 公共问题的解决方案 9.9.1. 对一个特定的 DataSource 使用错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 11.1....

    Spring API

    9.9. 常见问题的解决方法 9.9.1. 对一个特定的 DataSource 使用了错误的事务管理器 9.10. 更多的资源 10. DAO支持 10.1. 简介 10.2. 一致的异常层次 10.3. 一致的DAO支持抽象类 11. 使用JDBC进行数据访问 ...

    框架面试笔试问答题.docx

    Spring中定时任务的使用 - **@Scheduled**:用于标注在需要定时执行的方法上。 - **cron表达式**:定义任务执行的时间规则。 #### 25. Spring AOP注解 - **@Aspect**:定义一个切面。 - **@Before**:在目标方法...

Global site tag (gtag.js) - Google Analytics