问题描述
由于业务需求,公司使用 sqlserver 数据库。而且 xxl-job 分别被部署在了两天服务器上。导致了有时会出现同一个定时任务被重复执行的情况出现。
推荐阅读:xxl-job 使用 sqlserver数据库后,报警邮件失效
官方文档描述
- 一致性:“调度中心”通过DB锁保证集群分布式调度的一致性, 一次任务调度只会触发一次执行;
原因分析
定时任务被分别部署在【服务器 A、B】上,定时任务的数据库位于【服务器 C】上。而同一个定时任务被重复执行,说明分布式调度的【一致性】失效。
考虑到官方的 mysql 版本是通过 DB 锁保证的一致性,有可能是 sqlserver 不支持 mysql 的语法。
通过核心类【XxlJobScheduler】进入到定时任务的执行类【JobScheduleHelper】中,便能看到 mysql 的加锁语句。
- 具体实现见下方:
XxlJobScheduler
- JobScheduleHelper.getInstance().start():该方法是定时任务的执行
public class XxlJobScheduler {
private static final Logger logger = LoggerFactory.getLogger(XxlJobScheduler.class);
public void init() throws Exception {
JobScheduleHelper.getInstance().start();
}
}
JobScheduleHelper
改造前语句
在执行定时任务时,会通过 select xxx for update 对其进行加锁,而此 sql 语句在 sqlserver 中并不适用。
preparedStatement = conn.prepareStatement( "select * from xxl_job_lock where lock_name = 'schedule_lock' for update" );
改造后语句
SELECT * FROM xxl_job_lock WITH (TABLOCKX) WHERE lock_name = 'schedule_lock'