spring+hibernate下使用quartz出现no session的解决方法
在google上找了很久没有合适的解决办法,通常的建议是把hibernate的lazy改成false或者直接写sql。为了调度而启用lazy显然是不划算的。自己写sql,那就弃用了hibernate,两种方式都让人难以接收。最后看到一提示,spring可以使用OpenSessionInViewFilter和hibernateInterceptor来扩展hibernate的session,避免了我们在web请求的过程中出现no session的问题。借鉴hibernateInterceptor的做法,扩展QuartzJobBean就可以实现在非web环境下使用Quartz而不会出现no session的问题。
TransactionalQuartzTask的源码
public abstract class TransactionalQuartzTask extends QuartzJobBean {private static final Logger log = Logger.getLogger(TransactionalQuartzTask.class);// spring injected referenceprivate SessionFactory sessionFactory;public SessionFactory getSessionFactory() {return sessionFactory;}public void setSessionFactory(SessionFactory sessionFactory) {this.sessionFactory = sessionFactory;}/** * Most of this method is copied from the HibernateInterceptor. */protected final void executeInternal(JobExecutionContext ctx)throws JobExecutionException {Session session = SessionFactoryUtils.getSession(sessionFactory, true);boolean existingTransaction = SessionFactoryUtils.isSessionTransactional(session, getSessionFactory());if (existingTransaction) {log.info("Found thread-bound Session for TransactionalQuartzTask");} else {TransactionSynchronizationManager.bindResource(getSessionFactory(),new SessionHolder(session));}try {executeTransactional(ctx);} catch (HibernateException ex) {ex.printStackTrace();throw ex;} finally {if (existingTransaction) {log.debug("Not closing pre-bound Hibernate Session after TransactionalQuartzTask");} else {TransactionSynchronizationManager.unbindResource(getSessionFactory());SessionFactoryUtils.releaseSession(session, getSessionFactory());}}}/** * Implementing classes, implement this method. */protected abstract void executeTransactional(JobExecutionContext ctx)throws JobExecutionException;}
public class AutoBuildChannelRssTerminal extends TransactionalQuartzTask {private ChannelRssUtil channelRssUtil;public ChannelRssUtil getChannelRssUtil() {return channelRssUtil;}public void setChannelRssUtil(ChannelRssUtil channelRssUtil) {this.channelRssUtil = channelRssUtil;}private Logger log = Logger.getLogger(getClass());public void executeTransactional(JobExecutionContext ctx)throws JobExecutionException {channelRssUtil.buildChannelRss();}}
<bean id="buildChannelRssJob" value-ref="sessionFactory"></entry><entry key="channelRssUtil" value-ref="channelRssUtil"></entry></map></property></bean><bean id="simpleAutoBuildChannelRssTrigger" /></property><property name="repeatInterval"><value>300000</value></property></bean>