格雷尔斯(Grails)和石英(Quartz):长整型类型的值错误。

23

我正在尝试将quartz作业保存到数据库中。我已经设置了表格,并创建了quartz.properties文件,但当我尝试运行应用程序时,会出现以下异常:

2012-02-01 17:36:23,708 [main] ERROR context.GrailsContextLoader  - Error executing bootstraps: org.quartz.JobPersistenceException: Couldn't store trigger 'expirationTrigger' for 'com.pldtglobal.svngateway.ExpirationCheckerJob' job:Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000 [See nested exception: org.postgresql.util.PSQLException: Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000]
org.codehaus.groovy.runtime.InvokerInvocationException: org.quartz.JobPersistenceException: Couldn't store trigger 'expirationTrigger' for 'com.pldtglobal.svngateway.ExpirationCheckerJob' job:Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000 [See nested exception: org.postgresql.util.PSQLException: Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000]
    at org.grails.tomcat.TomcatServer.start(TomcatServer.groovy:212)
    at grails.web.container.EmbeddableServer$start.call(Unknown Source)
    at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy:158)
    at _GrailsRun_groovy$_run_closure5_closure12.doCall(_GrailsRun_groovy)
    at _GrailsSettings_groovy$_run_closure10.doCall(_GrailsSettings_groovy:280)
    at _GrailsSettings_groovy$_run_closure10.call(_GrailsSettings_groovy)
    at _GrailsRun_groovy$_run_closure5.doCall(_GrailsRun_groovy:149)
    at _GrailsRun_groovy$_run_closure5.call(_GrailsRun_groovy)
    at _GrailsRun_groovy.runInline(_GrailsRun_groovy:116)
    at _GrailsRun_groovy.this$4$runInline(_GrailsRun_groovy)
    at _GrailsRun_groovy$_run_closure1.doCall(_GrailsRun_groovy:59)
    at RunApp$_run_closure1.doCall(RunApp:33)
    at gant.Gant$_dispatch_closure5.doCall(Gant.groovy:381)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy:415)
    at gant.Gant$_dispatch_closure7.doCall(Gant.groovy)
    at gant.Gant.withBuildListeners(Gant.groovy:427)
    at gant.Gant.this$2$withBuildListeners(Gant.groovy)
    at gant.Gant$this$2$withBuildListeners.callCurrent(Unknown Source)
    at gant.Gant.dispatch(Gant.groovy:415)
    at gant.Gant.this$2$dispatch(Gant.groovy)
    at gant.Gant.invokeMethod(Gant.groovy)
    at gant.Gant.executeTargets(Gant.groovy:590)
    at gant.Gant.executeTargets(Gant.groovy:589)
Caused by: org.quartz.JobPersistenceException: Couldn't store trigger 'expirationTrigger' for 'com.pldtglobal.svngateway.ExpirationCheckerJob' job:Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000 [See nested exception: org.postgresql.util.PSQLException: Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000]
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1241)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$5.execute(JobStoreSupport.java:1147)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport$40.execute(JobStoreSupport.java:3670)
    at org.quartz.impl.jdbcjobstore.JobStoreCMT.executeInLock(JobStoreCMT.java:242)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.executeInLock(JobStoreSupport.java:3666)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1143)
    at org.quartz.core.QuartzScheduler.scheduleJob(QuartzScheduler.java:790)
    at org.quartz.impl.StdScheduler.scheduleJob(StdScheduler.java:254)
    at org.quartz.Scheduler$scheduleJob.call(Unknown Source)
    at QuartzGrailsPlugin$_closure5_closure24.doCall(QuartzGrailsPlugin.groovy:223)
    at QuartzGrailsPlugin$_closure5.doCall(QuartzGrailsPlugin.groovy:218)
    at QuartzGrailsPlugin.invokeMethod(QuartzGrailsPlugin.groovy)
    at QuartzGrailsPlugin$_closure3_closure21.doCall(QuartzGrailsPlugin.groovy:169)
    at QuartzGrailsPlugin$_closure3.doCall(QuartzGrailsPlugin.groovy:167)
    ... 23 more
Caused by: org.postgresql.util.PSQLException: Bad value for type long : \254\355\000\005sr\000\025org.quartz.JobDataMap\237\260\203\350\277\251\260\313\002\000\000xr\000&org.quartz.utils.StringKeyDirtyFlagMap\202\010\350\303\373\305](\002\000\001Z\000\023allowsTransientDataxr\000\035org.quartz.utils.DirtyFlagMap\023\346.\255(v\012\316\002\000\002Z\000\005dirtyL\000\003mapt\000\017Ljava/util/Map;xp\001sr\000\021java.util.HashMap\005\007\332\301\303\026`\321\003\000\002F\000\012loadFactorI\000\011thresholdxp?@\000\000\000\000\000\014w\010\000\000\000\020\000\000\000\001t\000'org.grails.plugins.quartz.grailsJobNamet\000.com.pldtglobal.svngateway.ExpirationCheckerJobx\000
    at org.postgresql.jdbc2.AbstractJdbc2ResultSet.toLong(AbstractJdbc2ResultSet.java:2796)
    at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getLong(AbstractJdbc2ResultSet.java:2019)
    at org.postgresql.jdbc4.Jdbc4ResultSet.getBlob(Jdbc4ResultSet.java:52)
    at org.postgresql.jdbc2.AbstractJdbc2ResultSet.getBlob(AbstractJdbc2ResultSet.java:335)
    at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.getObjectFromBlob(StdJDBCDelegate.java:3462)
    at org.quartz.impl.jdbcjobstore.StdJDBCDelegate.selectJobDetail(StdJDBCDelegate.java:904)
    at org.quartz.impl.jdbcjobstore.JobStoreSupport.storeTrigger(JobStoreSupport.java:1197)
    ... 36 more
Application context shutting down...
Application context shutdown.

我不知道实际问题出在哪里。当工作没有保存在数据库中时,代码是正确且运行良好的。


这个问题还没有被接受的答案。下面的回答对你有用吗?我也遇到了同样的问题,下面的建议对我不起作用。 - Michael D Johnson
@MichaelDJohnson 你解决了这个问题吗?怎么解决的? - vkg
6个回答

32

在你的 grails-app/conf/quartz.properties 文件中,替换

org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate

使用

org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

即使使用正确的代理,我仍然会遇到相同的错误,所以不能保证。


21
在Spring Boot中,您也可以使用以下属性在application.properties文件中指定PG驱动程序 -
spring.quartz.properties.org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

12

对于使用Quartz和Spring Boot的任何人,我在从Tomcat迁移到Spring Boot后遇到了相同的问题。在Tomcat中,我们使用了一个quartz属性文件,并在创建调度程序时手动加载它。其中之一是:

org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.PostgreSQLDelegate

在Spring Boot中,调度程序是通过自动配置自动创建的,因此我们的属性未被应用。

我们的解决方案是使用SchedulerFactoryBeanCustomizer并设置Quartz属性。这个自定义程序在调度程序创建之前应用,所以它是一个很好的配置Quartz的地方。

@Bean
public SchedulerFactoryBeanCustomizer schedulerFactoryBeanCustomizer()
{
  return new SchedulerFactoryBeanCustomizer()
  {
     @Override
     public void customize(SchedulerFactoryBean bean)
     {
        bean.setQuartzProperties(createQuartzProperties());
     }
  };
}

private Properties createQuartzProperties()
{
    // Could also load from a file
    Properties props = new Properties();
    props.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
    return props;
}

以下是我们迁移的完整quartz.properties文件,仅供参考:

org.quartz.scheduler.instanceName=ProcessAutomation
org.quartz.scheduler.instanceId=AUTO
org.quartz.scheduler.jmx.export=true
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=10
org.quartz.threadPool.threadPriority=5
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreCMT
org.quartz.jobStore.dataSource=QuartzDS
org.quartz.jobStore.nonManagedTXDataSource=springNonTxDataSource.ProcessAutomation
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate
org.quartz.jobStore.misfireThreshold=60000
org.quartz.jobStore.isClustered=true
org.quartz.jobStore.clusterCheckinInterval=20000

请问您能分享一下您使用的属性吗? - vkg
1
@vkg 确定,已将其添加到答案中。 - Mike

1
我也遇到过这个问题,我只需添加:
properties.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");

以下是完整的bean配置

@Bean
public SchedulerFactoryBean scheduler(Trigger... triggers) {
    SchedulerFactoryBean schedulerFactory = new SchedulerFactoryBean();

    Properties properties = new Properties();
    properties.setProperty("org.quartz.scheduler.instanceName", "MY_INSTANCE_NAME");
    properties.setProperty("org.quartz.scheduler.instanceId", "INSTANCE_ID_01");
    properties.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
    schedulerFactory.setOverwriteExistingJobs(true);
    schedulerFactory.setAutoStartup(true);
    schedulerFactory.setQuartzProperties(properties);
    schedulerFactory.setDataSource(dataSource);
    schedulerFactory.setJobFactory(springBeanJobFactory());
    schedulerFactory.setWaitForJobsToCompleteOnShutdown(true);

    if (ArrayUtils.isNotEmpty(triggers)) {
        schedulerFactory.setTriggers(triggers);
    }

    return schedulerFactory;
}

重要的是不仅要发布代码,还要包括代码的描述以及为什么建议使用它。这有助于他人理解代码的上下文和目的,并使其对阅读问题或答案的其他人更有用,@Sophea PHOS。 - DSDmark

1
@Bean
public Properties quartzProperties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    propertiesFactoryBean.setLocation(new ClassPathResource("application.properties"));
    Properties props = new Properties();
    props.put("org.quartz.jobStore.driverDelegateClass", "org.quartz.impl.jdbcjobstore.PostgreSQLDelegate");
    propertiesFactoryBean.setProperties(props);
    propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
}

如果您想设置所有石英属性,如集群、线程池等,请创建一个quartz.properties文件并使用以下内容:

@Autowired
private QuartzProperties quartzProperties;
@Autowired
DataSource dataSource;
@Bean
public SchedulerFactoryBean schedulerFactoryBean() throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
    factory.setOverwriteExistingJobs(true);
    factory.setDataSource(dataSource);
    factory.setQuartzProperties(quartzProperties());

    AutowiringSpringBeanJobFactory jobFactory = new AutowiringSpringBeanJobFactory();
    jobFactory.setApplicationContext(applicationContext);
    factory.setJobFactory(jobFactory);

    return factory;
}
@Bean
public Properties quartzProperties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    propertiesFactoryBean.setLocation(new ClassPathResource("/application.properties"));
    Properties props = new Properties();
    props.putAll(quartzProperties.getProperties());
    propertiesFactoryBean.setProperties(props);
    propertiesFactoryBean.afterPropertiesSet(); //it's important
    return propertiesFactoryBean.getObject();
}

以下是quartz.properties文件示例:
org.quartz.scheduler.instanceName=springBootQuartzApp org.quartz.scheduler.instanceId=AUTO org.quartz.threadPool.threadCount=50 org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.PostgreSQLDelegate org.quartz.jobStore.useProperties=true #org.quartz.jobStore.misfireThreshold=60000 org.quartz.jobStore.isClustered=true org.quartz.plugin.shutdownHook.class=org.quartz.plugins.management.ShutdownHookPlugin org.quartz.plugin.shutdownHook.cleanShutdown=TRUE

0

由于这个问题对我们来说确实很难修复,而且这些答案都没有帮助或引用Grails的特定内容,所以我会添加我们需要解决此问题的步骤:

在Grails 5.2.5项目中,我们是这样使用quartz插件的:

implementation("org.quartz-scheduler:quartz:2.2.3") {
    exclude group: 'slf4j-api', module: 'c3p0'
}
implementation ('org.grails.plugins:quartz:2.0.13')

Grails自带Spring框架和Spring自带的Quartz调度器,但我们需要关闭Spring的调度器,以免干扰我们自己的配置(有时候我们会发现相同的job被不同的调度器运行两次)。我认为这可能是因为它们读取了彼此的属性文件之类的。

为了关闭Spring的调度器,我们在application.yml中添加了以下内容:

spring:
    quartz:
        auto-startup: false

有所帮助。

然后我们在 application.groovy 中添加了此quartz配置:

quartz {
    jdbcStore = true // we needed this, because we were running more nodes and required jobs to run only once per set of nodes.
    autoStartup = false // autoStartup is set then to true per required environments.
    dataSource {
        quartzDataSource {
            driver = 'org.postgresql.Driver'
            maxConnections = 30
        }
    }
    scheduler.instanceName = 'ourInstanceName'
    scheduler.instanceId = 'AUTO'

    threadPool.'class' = 'org.quartz.simpl.SimpleThreadPool'
    threadPool.threadCount = 15
    threadPool.threadPriority = 5

    jobStore.'class' = 'org.quartz.impl.jdbcjobstore.JobStoreTX'
    jobStore.driverDelegateClass = 'org.quartz.impl.jdbcjobstore.PostgreSQLDelegate'
    jobStore.dataSource = 'quartzDataSource' // this references the above datasource. The name needs to match but can be arbitrary
    jobStore.useProperties = false
    jobStore.tablePrefix = 'qrtz_'
    jobStore.isClustered = true
    jobStore.clusterCheckinInterval = 5000

    plugin.shutdownhook.'class' = 'org.quartz.plugins.management.ShutdownHookPlugin'
    plugin.shutdownhook.cleanShutdown = true
}

然后,对于每个环境,我们会设置其余部分,例如:

environments {
    development {
        quartz {
            autoStartup = true
            dataSource {
                quartzDataSource {
                    user = 'grails'
                    password = 'grails'
                }
                quartzDataSource.URL = 'ourUrl' // I had to move URL outside like this, because if it was just URL without the prefix inside the above curly braces, the app wouldn't run with error "you tried to assign a value to the class 'java.net.URL'"
            }
        }
    }
}

有趣的是,各种石英属性直接设置在quartz节点中,而不是在quartz.propsquartz.properties节点中,就像以前一样。在那里不起作用。

如果您也需要它,这里是创建所需石英数据库表的脚本。我们已经寻找了一段时间。 https://github.com/quartznet/quartznet/blob/main/database/tables/tables_postgres.sql


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接