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 reference
	private 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;

}


    具体的job类,继承了TransactionalQuartzTask。此处需要注意的是成员变量channelRssUtil不能通过标注@Autowired来装配,否则会报错。
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();
	}
}


在spring中的配置
<bean id="buildChannelRssJob" class="org.springframework.scheduling.quartz.JobDetailBean">
		<property name="jobClass">
			<value>cn.com.people.tv.pvms.system.AutoBuildChannelRssTerminal
			</value>
		</property>
		<property name="jobDataAsMap">
			<map>
				<entry key="sessionFactory" value-ref="sessionFactory"></entry>
				<entry key="channelRssUtil" value-ref="channelRssUtil"></entry>
			</map>
		</property>
	</bean>
<bean id="simpleAutoBuildChannelRssTrigger" class="org.springframework.scheduling.quartz.SimpleTriggerBean">
		<property name="jobDetail">
			<ref bean="buildChannelRssJob" />
		</property>
		<property name="repeatInterval">
			<value>300000</value>
		</property>
	</bean>



你可能感兴趣的:(spring,sql,Hibernate,Web,quartz)