【问题标题】:How do you update a value in a Quartz JobDataMap?如何更新 Quartz JobDataMap 中的值?
【发布时间】:2011-04-29 17:45:11
【问题描述】:

我正在使用石英调度程序 1.8.5。我创建了一个实现 StatefulJob 的作业。我使用 SimpleTrigger 和 StdSchedulerFactory 安排作业。

似乎除了 JobDetail 的 JobDataMap 之外,我还必须更新 Trigger 的 JobDataMap 才能从 Job 内部更改 JobDataMap。我试图理解为什么有必要同时更新两者?我注意到 JobDataMap 设置为脏。也许我必须明确保存它或其他什么?

我想我必须深入研究 Quartz 的源代码才能真正了解这里发生了什么,但我想我会偷懒并先问。感谢您深入了解 JobDataMap 的内部工作原理!

这是我的工作:

public class HelloJob implements StatefulJob {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        int count = context.getMergedJobDataMap().getInt("count");
        int count2 = context.getJobDetail().getJobDataMap().getInt("count");
        //int count3 = context.getTrigger().getJobDataMap().getInt("count");
        System.err.println("HelloJob is executing. Count: '"+count+"', "+count2+"'");

        //The count only gets updated if I updated both the Trigger and 
                // JobDetail DataMaps. If I only update the JobDetail, it doesn't persist. 
        context.getTrigger().getJobDataMap().put("count", count++);
        context.getJobDetail().getJobDataMap().put("count", count++);

        //This has no effect inside the job, but it works outside the job
        try {
            context.getScheduler().addJob(context.getJobDetail(), true);
        } catch (SchedulerException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        //These don't seem to persist between jobs
        //context.put("count", count++);
        //context.getMergedJobDataMap().put("count", count++);
    }
}

我是这样安排工作的:

try {
    // define the job and tie it to our HelloJob class
    JobDetail job = new JobDetail(JOB_NAME, JOB_GROUP_NAME,
            HelloJob.class);
    job.getJobDataMap().put("count", 1);
    // Trigger the job to run now, and every so often
    Trigger trigger = new SimpleTrigger("myTrigger", "group1",
            SimpleTrigger.REPEAT_INDEFINITELY, howOften);

    // Tell quartz to schedule the job using our trigger
    sched.scheduleJob(job, trigger);
    return job;
} catch (SchedulerException e) {
    throw e;
}

更新:

似乎我必须将值放入 JobDetail 的 JobDataMap 两次才能使其持久化,这是可行的:

public class HelloJob implements StatefulJob {

    public HelloJob() {
    }

    public void execute(JobExecutionContext context)
            throws JobExecutionException {

        int count = (Integer) context.getMergedJobDataMap().get("count");
        System.err.println("HelloJob is executing. Count: '"+count+"', and is the job stateful? "+context.getJobDetail().isStateful());
        context.getJobDetail().getJobDataMap().put("count", count++);
        context.getJobDetail().getJobDataMap().put("count", count++);
    }
}

这似乎是一个错误,也许?或者也许我缺少一个步骤来告诉 JobDetail 将其 JobDataMap 的内容刷新到 JobStore?

【问题讨论】:

    标签: java quartz-scheduler


    【解决方案1】:

    我认为您的问题在于使用后缀 ++ 运算符 - 当您这样做时:

    context.getJobDetail().getJobDataMap().put("count", count++);  
    

    您将地图中的值设置为计数,然后递增计数。

    在我看来你想要的:

    context.getJobDetail().getJobDataMap().put("count", ++count);  
    

    只需要执行一次。

    【讨论】:

    • 谢谢,这就是问题所在。我不敢相信我没有抓住那个。非常感谢!
    • 这个答案让我免于沮丧,非常感谢老兄! +1 赞成票 ;)
    • 此外,您不需要 getTrigger 中的 JobDatamap
    【解决方案2】:

    如您所知,在 Quartz 中,触发器和作业是分开的,而不是与一些调度程序结合在一起。他们可能允许您向数据映射添加特定于触发器级别而不是作业级别的值,等等。

    我认为它允许您使用不同的数据集执行相同的最终作业,但在作业级别仍然有一些公共数据。

    【讨论】:

    • 感谢您的回答,这是有道理的。但奇怪的是,当我只做 context.getJobDetail.getJobDataMap.put(blah) 时,它不会持续存在。同样,当我只做 context.getTrigger.getJobDataMap.put(blah) 时,它也不会持续存在。我必须同时更新 Trigger 和 JobDetail JobDataMap 才能使其持续存在。我想我只需要更新一个或另一个。但我一定不明白。
    【解决方案3】:

    正如 scpritch76 回答的那样,作业和触发器是分开的,因此给定作业可以有许多触发器(计划)。

    作业可以在 JobDataMap 中具有一些基本属性集,然后触发器可以在其 JobDataMap 中为作业的特定执行提供附加属性(或覆盖基本属性)。

    【讨论】:

    • 谢谢,是的,我记得在quartz-scheduler.org 网站上读到,触发器JobDataMap 中定义的键/值对将优先于JobDetail 中定义的键/值对。但是,我的问题是我似乎必须在两个地方都设置键/值对才能使其在作业执行之间持续存在(请参阅我对 @cspritch76 的评论)。再次感谢您的帮助。
    • 只有 Job 的 JobDataMap 在执行之间重新保留(如果作业是有状态的)。
    • 如果要更新触发器的JobDataMap,必须重新存储触发器(scheduler.rescheduleJob(..))。
    • 啊,这是有道理的,您必须重新安排作业以更新触发器的 JobDataMap,谢谢。我更新了我的问题。似乎如果我手动创建一个新的 JobDataMap 并明确设置它,那么更改仍然存在。我认为这里可能存在错误,也许?
    【解决方案4】:
    @PersistJobDataAfterExecution
    @DisallowConcurrentExecution
    public class DynamicTestJob implements Job
    {
    
        private static final Logger log = LoggerFactory.getLogger(DynamicTestJob.class);
    
        @Override
        public void execute(final JobExecutionContext context)
        {
            final JobDataMap jobDataMap = context.getJobDetail().getJobDataMap();
            Integer counter = (Integer) jobDataMap.get("counter");
    
            if (counter == null)
            {
                counter = 1;
            }
            else
            {
                counter++;
            }
    
            jobDataMap.put("counter", counter);
    
            System.out.println(counter);
        }
    
    }
    

    【讨论】:

    • 这是适用于我的场景的答案。 @PersistJobDataAfterExecution 是解决方案。谢谢兄弟!。
    猜你喜欢
    • 2016-05-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多