У меня есть требование разработать загрузочную партию с использованием кварца в качестве планировщика. Я создал приложение Spring Batch, а также настроил кварц для запуска задания и сохранения данных задания / запуска в таблицах RDBMS, связанных с кварцем.
Загрузочное приложение Spring запускается успешно, но при запуске задания в соответствии с настройкой cron. Она выдает ошибку ниже.
2020-04-27 20:42:09.967 INFO 1460 --- [ main] c.b.g.batch.IemsBatchApplication : Started IemsBatchApplication in 12.112 seconds (JVM running for 13.22)
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
Я не могу найти причину root, поэтому приложение пытается сохранить данные в таблице метаданных пружины, а не в кварцевых таблицах. Кварц связанные таблицы уже созданы в моей БД. Пожалуйста, помогите мне.
Пожалуйста, найдите ниже код для того же.
@Configuration
public class BatchSchedulerConfig {
@Autowired
@Qualifier("batchDataSource")
private DataSource batchDataSource;
@Autowired
JobLauncher jobLauncher;
@Autowired
JobLocator jobLocator;
@Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(BatchJobLauncherConfig.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("jobName", IEMSBatchConstant.MonthlyElectricityMeterReadingJob);
jobDetailFactoryBean.setJobDataAsMap(map);
jobDetailFactoryBean.setGroup("etl_group");
jobDetailFactoryBean.setName("etl_job");
return jobDetailFactoryBean;
}
@Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
cronTriggerFactoryBean.setStartDelay(3000);
cronTriggerFactoryBean.setName("cron_trigger");
cronTriggerFactoryBean.setGroup("cron_group");
cronTriggerFactoryBean.setCronExpression("0 0/2 * 1/1 * ? *");
return cronTriggerFactoryBean;
}
@Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean) throws IOException {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
Map<String, Object> map = new HashMap<String, Object>();
map.put("joblocator", jobLocator);
map.put("JobLauncher", jobLauncher);
scheduler.setSchedulerContextAsMap(map);
scheduler.setTriggers(cronTriggerFactoryBean.getObject());
scheduler.setDataSource(batchDataSource);
scheduler.setQuartzProperties(quartzProperties());
// scheduler.setSchedulerName(schedulerName);
return scheduler;
}
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
}
@Configuration
@EnableConfigurationProperties
public class BatchBaseConfig {
private static final Logger log = LoggerFactory.getLogger(BatchBaseConfig.class);
@Bean
public JobLauncher jobLauncher(JobRepository jobRepository) throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository);
return simpleJobLauncher;
}
@Bean
public JobRepository jobRepository(DataSource batchDataSource) throws Exception {
DataSourceTransactionManager batchTransactionManager = new DataSourceTransactionManager();
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
batchTransactionManager.setDataSource(batchDataSource);
jobRepositoryFactoryBean.setTransactionManager(batchTransactionManager);
jobRepositoryFactoryBean.setDatabaseType(DatabaseType.ORACLE.getProductName());
//jobRepositoryFactoryBean.setIsolationLevelForCreate("ISOLATION_DEFAULT");
jobRepositoryFactoryBean.setDataSource(batchDataSource);
jobRepositoryFactoryBean.setTablePrefix("QRTZ_");
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
@Bean(name = "batchDataSource")
@Primary
@ConfigurationProperties(prefix = "quartz")
public DataSource batchDataSource() {
DataSource batchDbSrc = DataSourceBuilder.create().build();
return batchDbSrc;
}
@Bean(name = "appDataSource")
@ConfigurationProperties(prefix = "app")
public DataSource appDataSource() {
DataSource appDbSrc = DataSourceBuilder.create().build();
return appDbSrc;
}
@Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
return jobRegistryBeanPostProcessor;
}
}
@Getter
@Setter
public class BatchJobLauncherConfig extends QuartzJobBean {
private static final Logger log = LoggerFactory.getLogger(BatchJobLauncherConfig.class);
private JobLauncher jobLauncher;
private JobLocator joblocator;
private String jobName;
@Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
JobExecution jobExecution = jobLauncher.run(joblocator.getJob(jobName), new
JobParameters());
log.info("{}_{} was completed successfully", jobExecution.getJobConfigurationName(),
jobExecution.getId());
} catch (JobExecutionAlreadyRunningException | JobRestartException |
JobInstanceAlreadyCompleteException
| JobParametersInvalidException | NoSuchJobException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Configuration
public class JobConfig {
private static final Logger log = LoggerFactory.getLogger(JobConfig.class);
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private ReadingFromDB readingFromDB;
@Autowired
private ReadingFileWriter readingFileWriter;
@Qualifier(value = "meterReadingJob")
@Bean
public Job meterReadingJob() throws Exception {
log.info("Enter into meterReadingJob method ");
return this.jobBuilderFactory.get("meterReadingJob")
.start(createReadingFile()).build();
}
@Bean
public Step createReadingFile() throws Exception {
return this.stepBuilderFactory.get("createReadingFile").chunk(1)
.reader(readingFromDB).writer(readingFileWriter).build();
}
}
Application.properties
spring.batch.job.enabled=false
spring.main.allow-bean-definition-overriding=true
#Spring's default configuration to generate datasource
app.jdbcUrl=jdbc:oracle:thin:@//<Removed>
app.username=<Removed>
app.password=<Removed>
app.driverClassName=oracle.jdbc.OracleDriver
spring.app.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
#Quartz dataSource
quartz.jdbcUrl=jdbc:oracle:thin:@//<Removed>
quartz.username=<Removed>
quartz.password=<Removed>
quartz.driverClassName=oracle.jdbc.OracleDriver
Quartz.properties
#scheduler name will be "MyScheduler"
org.quartz.scheduler.instanceName=MyNewScheduler
org.quartz.scheduler.instanceId=AUTO
#maximum of 3 jobs can be run simultaneously
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=50
#Quartz persistent jobStore config
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
#org.quartz.jobStore.dataSource=batchDataSource
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.isClustered=false
Оба источника данных создаются и записи также собираются для триггеры и задания в именах источников данных batchDataSource. Проблема возникает, когда задание запускается и пакет пытается вставить сведения о задании в БД.
Заранее спасибо.