spring-quartz使用过程中出现Failure obtaining db row lock异常的分析及解决

就在今天,在项目中配置spring-quartz定时任务的时候,出现了一个以前没有遇到过的错误:

ERROR [org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:205)] Context initialization failed

org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘quartzScheduler’ defined in ServletContext resource [/WEB-INF/classes/spring-quartz.xml]: Invocation of init method failed; nested exception is org.quartz.SchedulerConfigException: Failure occured during job recovery. [See nested exception: org.quartz.impl.jdbcjobstore.LockException: Failure obtaining db row lock: ORA-00942: table or view does not exist

这是一个很奇怪的错误,从打印的异常信息可以看出:quartz试图将任务执行情况持久化到数据库中(一般是在集群环境中使用的一种同步任务的方法,保证某一时刻集群中只有一台机器执行定时任务,当然,这不是很优雅,有悖于集群的思想)。

但是,令我奇怪的是,第一,我没有配置quartz的数据源信息;第二,我也没有配置quartz的cluster,quartz应该是在内存中维护任务列表才对。

于是看了看spring与quartz相关的文档,试图在schedulerfactorybean的声明中加上这么一段,来强制quartz不使用数据库而是在内存中:

<property name=”quartzProperties”>

<props>

<prop key=”org.quartz.jobStore.class”>

org.quartz.simpl.RAMJobStore

</prop>

</props>

</property>

发现还是不行,问题依旧。再看看SchedulerFactoryBean的doc,一股怒火直冲上来。doc里setDataSource方法这么写的:

Set the default DataSource to be used by the Scheduler. If set, this will override corresponding settings in Quartz properties.

意思是,如果你为它设置了数据源,那么它会覆盖quartz配置文件中相应的属性。

不过我的配置没有给它添加数据源啊!后来仔细一想,之前曾经遇到过,在spring的bean的自动装配为autodetect时,spring有过不知道将两个map中的哪一个注射到某bean中(实际情况是,那个map不需注入,只不过autodetect了,spring自作聪明了),后来通过自动装配的byName解决问题。原来又是自动装配惹的祸了,很遗憾的,我的项目里的数据源的声明恰好叫做”dataSource”,又被spring自作主张的注射到SchedulerFactoryBean里面了,霸道,太霸道了。

没办法,改datasource的名字不太合适,只好把SchedulerFactoryBean的autowire改为no,问题解决。

题外话,cy有一篇文章,指出spring的autodetect装配属性效率相当低下。参见《Webwork2的Action使用Spring的default-autowire prototype­获取的性能对比

加载评论框需要翻墙