环境
- Quartz集群模式,使用数据库持久化任务
- Spring接管Quartz,即Quartz依赖于Spring运行
问题
在一套集群应用(4个实例节点)启动的时候,应用调用了QuartzScheduler#scheduleJob初始化定时任务,会偶然触发JobPersistenceException: could not store trigger : unique constraint violdated.即多个节点同时scheduleJob的时候了违反约束条件.
问题代码大概如下:
public class MyQuartzConfig {
@Autowired
private Scheduler scheduler;
public void init() {
scheduler.scheduleJob(job, trigger);
}
}
我们都知道,Quartz集群模式是借用了数据库来实现竞争锁的,如果某个节点获取锁失败,会等待一段时间后再次尝试,直到超过重试次数抛出异常.上述出现违反约束条件肯定是因为锁没有生效,换句话说事务没有生效
原因
Quartz JobStore
Quartz提供了两个持久化任务的实现类,分别是JobStoreCMT和JobStoreTX
- JobStoreTX很简单,里面只有一个数据源,持久化的事务提交和回滚都由它来控制
- JobStoreCMT有两个数据源,一个数据源TxDataSource,即包含事务的数据源,另一个NonTxDataSource,不包含事务的数据源
JobStoreCMT的两个数据源怎么理解呢?根据官方注释可以看到,TxDataSource事务受容器管理,可应用于JTA等XA场合. 而NonTxDataSource事务不受容器管理,是Quartz自行管理.
小结:CMT的NonTxDataSource即是JobStoreTX的数据源,Quartz获取connection后会设置autoCommit=false,由Quartz自行控制事务.
而JobStoreCMT的TxDataSource是额外添加的,为的是让用户能够控制这些事务,给用户更大的灵活性.
JobStore在不同的场景下都会用到这两种数据源,分别是executeInLock和executeInNonManagedTXLock
- executeInLock,与TxDataSource对应,基本上是提供给用户调用的API
- executeInNonManagedTXLock,与NonTxDataSource对应,都是Quartz内部的API,与用户无关
Spring-Quartz
当Spring接管Quartz后,情况会发生一些变化. 如果Spring提供的SchedulerFactoryBean设置了数据源,就会用LocalDataSourceJobStore来替代Quartz的JobStore类.
LocalDataSourceJobStore其实是一个JobStoreCMT,它的TxDataSource受Spring事务管理,NonTxDataSource则不会.
同时他会将从TxDataSource获取的connection.autoCommit=ture
真正原因
看到这里应该能猜到原因了,在我们的例子里,调用scheduleJob方法使用的数据源是TxDataSource,而持久化类LocalDataSourceJobStore默认autoCommit=ture,在这种情况下其实我们调用时是不存在事务的,自然就会出现文中的问题.
解决问题
没有事务的话给它加上事务就好了,由于我们用到Spring-Quartz,加上Spring的事务就能解决问题
public class MyQuartzConfig {
@Autowired
private Scheduler scheduler;
@Transactional // 加上事务注解即可解决问题
public void init() {
scheduler.scheduleJob(job, trigger);
}
}
总结
Quartz提供JobStoreCMT是为了让用户调用Quartz的时候有事务控制(例如希望多个Quartz实例同时成功或同时失败).
我也不知道以后怎么避免这类问题,Spring提供的文档好像没有说明事务的问题,难道真的只能好好看注释了?
今天的文章Spring-Quartz事务问题的排查总结分享到此就结束了,感谢您的阅读。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/21920.html