当前位置:   article > 正文

使用SpringBoot启动SpringBatch,启动过程源代码分析_cannot find any job execution for job instance

cannot find any job execution for job instance

目录

一.POM

二.表构造说明

・ER图

・ER图生成  (使用Eclipse重点 ERMaster插件)

・还有三个序列(Mysql使用表)

・【BATCH_JOB_EXECUTION_PARAMS】 表的说明

・发生问题的原因

・代码分析的目的

 ・【run.id】

 ・【JobInstanceID】

三.启动类,参数 (使用Eclipse中的【実行の構成】(Run Configurantions) )

四.Spring框架类

0.使用到的jar

1.SpringApplication.java [ spring-boot-xxx.jar] 

 ★ 有 ①【ApplicationRunner】,②【CommandLineRunner】两种形式 ★

2.JobLauncherApplicationRunner.java [ spring-boot-autoconfigure-xxx.jar] 

launchJobFromProperties(Properties properties)

【这里的Log参数,会抹去所有的Spring的参数】 

      ★扩展:args.getNonOptionArgs(); // 获取没有key的值   ===START

executeLocalJobs(JobParameters jobParameters) 

execute(Job job, JobParameters jobParameters)

JobParameters getNextJobParameters(Job job, JobParameters jobParameters) 

3.JobParametersBuilder.java [ spring-batch-core-xxx.jar] 

getNextJobParameters(Job job)

★★★★★★★关于参数  parameters中的 【所有】参数的取得 ★★★★★★★

     根据 上次的运行结果,获取 参数的值

      (具体:

4.RunIdIncrementer.java   [ spring-boot-core-xxx.jar] 

★★★取得已经存在的run.id、加1处理,不存在的话,初始值1★★★

getNext(@Nullable JobParameters parameters) {

2.JobLauncherApplicationRunner.java(继续执行) [ spring-boot-autoconfigure-xxx.jar]

★★★关于参数  parameters中的 run.id  ★★★

5.SimpleJobLauncher.java

run(final Job job, final JobParameters jobParameters)

【这里的Log参数,与Batch启动时,传入的参数无关,与上一次的参数有关】 

6.SimpleJobRepository.java [30行]

createJobExecution(String jobName, JobParameters jobParameters)

★★★本次整理原因★★★由于【run.id】对应的值过小,出现行下面9行(大段代码26行)的如下错误

JobInstance jobInstance = this.jobInstanceDao.getJobInstance(jobName, jobParameters);

7.JdbcJobInstanceDao.java  9行

getJobInstance(String jobName, JobParameters jobParameters)

  ★★  ★★  ★★ 如果生成了和以前 (同JobName)重复的值 ,就凉凉了,系统一定会报错  ★★  ★★  ★★ 

7.1 DefaultJobKeyGenerator.java

7.JdbcJobInstanceDao.java  15行

   ★★★↓出错根本原因(Cannot find any job execution for job instance: )★★★

6.SimpleJobRepository.java (继续执行) [55行]

8.JdbcJobInstanceDao.java

createJobInstance(String jobName, JobParameters jobParameters) {

6.SimpleJobRepository.java (继续执行) [65行]

createJobExecution(String jobName, JobParameters jobParameters)

9.JdbcJobExecutionDao.java

saveJobExecution(JobExecution jobExecution) {

insertParameter(Long executionId, ParameterType type, String key, Object value, boolean identifying) {

五.模拟 生成 JOB_KEY  的代码

六.删除各表数据时,要按照顺序删除

七.问题解决方法

八.扩展:更多Java知识


一.POM

  1. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
  2. <modelVersion>4.0.0</modelVersion>
  3. <groupId>com.sxz</groupId>
  4. <artifactId>test001</artifactId>
  5. <version>0.0.1-SNAPSHOT</version>
  6. <properties>
  7. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  8. </properties>
  9. <parent>
  10. <groupId>org.springframework.boot</groupId>
  11. <artifactId>spring-boot-starter-parent</artifactId>
  12. <version>2.3.10.RELEASE</version>
  13. </parent>
  14. <dependencies>
  15. <dependency>
  16. <groupId>org.springframework.boot</groupId>
  17. <artifactId>spring-boot-starter-web</artifactId>
  18. </dependency>
  19. <dependency>
  20. <groupId>org.springframework.boot</groupId>
  21. <artifactId>spring-boot-starter-batch</artifactId>
  22. </dependency>
  23. <dependency>
  24. <groupId>org.springframework.boot</groupId>
  25. <artifactId>spring-boot-starter-thymeleaf</artifactId>
  26. </dependency>
  27. <dependency>
  28. <groupId>junit</groupId>
  29. <artifactId>junit</artifactId>
  30. <scope>test</scope>
  31. </dependency>
  32. </dependencies>
  33. <build>
  34. <plugins>
  35. <plugin>
  36. <groupId>org.springframework.boot</groupId>
  37. <artifactId>spring-boot-maven-plugin</artifactId>
  38. <configuration>
  39. <includeSystemScope>true</includeSystemScope>
  40. </configuration>
  41. </plugin>
  42. </plugins>
  43. </build>
  44. </project>

---

二.表构造说明

・ER图

从【BATCH_JOB_INSTANCE】 表开始(这个表只有一条记录,对应其它表,多条记录)

・ER图生成  (使用Eclipse重点 ERMaster插件)

Eclipse中的,ER图生成工具:【ERMaster】_sun0322的博客-CSDN博客

・还有三个序列(Mysql使用表)

SpringBatch学习_sun0322的博客-CSDN博客

  1. CREATE TABLE BATCH_JOB_SEQ (ID BIGINT NOT NULL) type=InnoDB;
  2. INSERT INTO BATCH_JOB_SEQ values(0);
  3. CREATE TABLE BATCH_JOB_EXECUTION_SEQ (ID BIGINT NOT NULL) type=InnoDB;
  4. INSERT INTO BATCH_JOB_EXECUTION_SEQ values(0);
  5. CREATE TABLE BATCH_STEP_EXECUTION_SEQ (ID BIGINT NOT NULL) type=InnoDB;
  6. INSERT INTO BATCH_STEP_EXECUTION_SEQ values(0);

----

报下面错误时

ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'type=InnoDB' at line 1

使用下面语句

  1. CREATE TABLE BATCH_JOB_SEQ (ID BIGINT NOT NULL) ENGINE=InnoDB;
  2. INSERT INTO BATCH_JOB_SEQ values(0);
  3. CREATE TABLE BATCH_JOB_EXECUTION_SEQ (ID BIGINT NOT NULL) ENGINE=InnoDB;
  4. INSERT INTO BATCH_JOB_EXECUTION_SEQ values(0);
  5. CREATE TABLE BATCH_STEP_EXECUTION_SEQ (ID BIGINT NOT NULL) ENGINE=InnoDB;
  6. INSERT INTO BATCH_STEP_EXECUTION_SEQ values(0);

・【BATCH_JOB_EXECUTION_PARAMS】 表的说明

・一个JOB_EXECUTION_ID,可用对应多条记录(record)

・每条记录的【KEY_NAME】不相同

・一般,有一条记录的【KEY_NAME】为「run.id」,对应的值【LONG_VAL】有值, 是「数字」

・但是使用Junit执行时,没有「run.id」,取代它的是「random」

・其他的记录,是启动时的参数,比如【KEY_NAM】spring.batch.job.names、对应的值【STRING_VAL】有值, 是「yourJobName」

・发生问题的原因

下面前5个表的数据都被删除了,只有第六个表的数据没有被删除。

  1. delete from BATCH_JOB_EXECUTION_PARAMS;
  2. delete from BATCH_STEP_EXECUTION_CONTEXT;
  3. delete from BATCH_JOB_EXECUTION_CONTEXT;
  4. delete from BATCH_STEP_EXECUTION;
  5. delete from BATCH_JOB_EXECUTION;
  6. -- delete from BATCH_JOB_INSTANCE;

因为都被删除了,

所以,run.id从1开始, 在第六个表【BATCH_JOB_INSTANCE】中,找到了数据。

但是,其它表中的数据都已经被删除了,所以,Log中,出了下面的错误

Cannot find any job execution for job instance: id= XXXX

这个instance id 就是,第六个表【BATCH_JOB_INSTANCE】中的值。

根据下面的分析得知,【BATCH_JOB_INSTANCE】的JOB_KEY由[run.id=1;]生成。

而,同一个JOB_NAME有重复的JOB_KEY,在运行的时候,就会使用之前的这JOB_KEY对应的JOB_INSTANCE_ID、因此,就产生了问题。

・代码分析的目的

 ・【run.id】

问:【BATCH_JOB_EXECUTION_PARAMS】 表中,KEY_NAME为【run.id】时,对应的值,LONG_VAL是如何【発番】的

答:如果都被删除,从1开始

 ・【JobInstanceID

问:【BATCH_JOB_EXECUTION_PARAMS】 表中,【run.id】的值,如果都被删除了,重新从1开始,对JobInstanceID是否有影响。

答:影响

三.启动类,参数 (使用Eclipse中的【実行の構成】(Run Configurantions) )

 启动类(Main Class):

     被@SpringBootApplication标注的类

参数(Arugments):

--spring.profiles.active=prod   --spring.batch.job.names=yourJobName --spring.config.location=xxx\xxx\xxx\application.yml

  

四.Spring框架类

0.使用到的jar

---

1.SpringApplication.java [ spring-boot-xxx.jar] 

下面的25行 执行

  1. public class SpringApplication {
  2. .......
  3. public ConfigurableApplicationContext run(String... args) {
  4. StopWatch stopWatch = new StopWatch();
  5. stopWatch.start();
  6. ConfigurableApplicationContext context = null;
  7. configureHeadlessProperty();
  8. SpringApplicationRunListeners listeners = getRunListeners(args);
  9. listeners.starting();
  10. try {
  11. ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
  12. ConfigurableEnvironment environment = prepareEnvironment(listeners, applicationArguments);
  13. configureIgnoreBeanInfo(environment);
  14. Banner printedBanner = printBanner(environment);
  15. context = createApplicationContext();
  16. prepareContext(context, environment, listeners, applicationArguments, printedBanner);
  17. refreshContext(context);
  18. afterRefresh(context, applicationArguments);
  19. stopWatch.stop();
  20. if (this.logStartupInfo) {
  21. new StartupInfoLogger(this.mainApplicationClass).logStarted(getApplicationLog(), stopWatch);
  22. }
  23. listeners.started(context);
  24. callRunners(context, applicationArguments);
  25. }
  26. catch (Throwable ex) {
  27. handleRunFailure(context, ex, listeners);
  28. throw new IllegalStateException(ex);
  29. }
  30. try {
  31. listeners.running(context);
  32. }
  33. catch (Throwable ex) {
  34. handleRunFailure(context, ex, null);
  35. throw new IllegalStateException(ex);
  36. }
  37. return context;
  38. }

---

下面的11行 执行

 ★ 有 ①【ApplicationRunner】,②【CommandLineRunner】两种形式 ★

spring boot:ApplicationRunner和CommandLineRunner用法区别_小贼驴的博客-CSDN博客

业务场景:
应用服务启动时,加载一些数据和执行一些应用的初始化动作。如:删除临时文件,清除缓存信息,读取配置文件信息,数据库连接等。
1、SpringBoot提供了CommandLineRunner和ApplicationRunner接口。当接口有多个实现类时,提供了@order注解实现自定义执行顺序,也可以实现Ordered接口来自定义顺序。
注意:数字越小,优先级越高,也就是@Order(1)注解的类会在@Order(2)注解的类之前执行。
两者的区别在于:
ApplicationRunner中run方法的参数为ApplicationArguments,而CommandLineRunner接口中run方法的参数为String数组。想要更详细地获取命令行参数,那就使用ApplicationRunner接口

  1. 共同点:
  2. 其一 执行时机都是在容器启动完成的时候进行执行;其二 这两个接口中都有一个run()方法;
  3. 如果程序里既有ApplicationRunner ,也有CommandLineRunner代码 ,
  4. 则ApplicationRunner 先运行,而CommandLineRunner 后运行。
  5. 不同点:
  6. ApplicationRunner中run方法的参数为ApplicationArguments,
  7. 而CommandLineRunner接口中run方法的参数为String数组。
  8. 问题提出: 如果有多个实现类,而我们需要按照一定的顺序执行的话,那么应该怎么办呢?
  9. 解决方案:
  10. 方法1)可以在实现类上加上@Order注解指定执行的顺序;
  11. 方法2)可以在实现类上实现Ordered接口来标识。
  12. 需要注意:数字越小,优先级越高,也就是@Order(1)注解的类会在@Order(2)注解的类之前执行。

这里①被执行 (下面代码第11行)

  1. public class SpringApplication {
  2. .......
  3. private void callRunners(ApplicationContext context, ApplicationArguments args) {
  4. List<Object> runners = new ArrayList<>();
  5. runners.addAll(context.getBeansOfType(ApplicationRunner.class).values());
  6. runners.addAll(context.getBeansOfType(CommandLineRunner.class).values());
  7. AnnotationAwareOrderComparator.sort(runners);
  8. for (Object runner : new LinkedHashSet<>(runners)) {
  9. if (runner instanceof ApplicationRunner) {
  10. callRunner((ApplicationRunner) runner, args);
  11. }
  12. if (runner instanceof CommandLineRunner) {
  13. callRunner((CommandLineRunner) runner, args);
  14. }
  15. }
  16. }

---

  1. public class SpringApplication {
  2. .......
  3. private void callRunner(ApplicationRunner runner, ApplicationArguments args) {
  4. try {
  5. (runner).run(args);
  6. }
  7. catch (Exception ex) {
  8. throw new IllegalStateException("Failed to execute ApplicationRunner", ex);
  9. }
  10. }

---

2.JobLauncherApplicationRunner.java [ spring-boot-autoconfigure-xxx.jar] 

launchJobFromProperties(Properties properties)

下面的 11,16,21,22 行  依次 被 执行

第6行的方法中,会舍弃 【--xxx=xxx】的所有参数!!!

所以,根据第17行显示如下Log信息

【这里的Log参数,会抹去所有的Spring的参数】 

o.s.b.a.b.JobLauncherApplicationRunner Running default command line with:[]

----

  1. public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered, ApplicationEventPublisherAware {
  2. /**
  3. * The default order for the command line runner.
  4. */
  5. public static final int DEFAULT_ORDER = 0;
  6. .......
  7. @Override
  8. public void run(ApplicationArguments args) throws Exception {
  9. String[] jobArguments = args.getNonOptionArgs().toArray(new String[0]);
  10. run(jobArguments);
  11. }
  12. public void run(String... args) throws JobExecutionException {
  13. logger.info("Running default command line with: " + Arrays.asList(args));
  14. launchJobFromProperties(StringUtils.splitArrayElementsIntoProperties(args, "="));
  15. }
  16. protected void launchJobFromProperties(Properties properties) throws JobExecutionException {
  17. JobParameters jobParameters = this.converter.getJobParameters(properties);
  18. executeLocalJobs(jobParameters);
  19. executeRegisteredJobs(jobParameters);
  20. }
  21. .......

---

      ★扩展:args.getNonOptionArgs(); // 获取没有key的值   ===START

启动jar包

java -jar hello.jar --name=sxz --age=2 hello word

====

  1. @Component
  2. @Order(99)
  3. public class MyApplicationRunner01 implements ApplicationRunner {
  4. @Override
  5. public void run(ApplicationArguments args) throws Exception {
  6. String[] sourceArgs = args.getSourceArgs();//获取启动的所有参数
  7. System.out.println("sourceArgs:" + Arrays.toString(sourceArgs));
  8. List<String> nonOptionArgs = args.getNonOptionArgs(); // 获取没有key的值
  9. System.out.println("nonOptionArgs:" + nonOptionArgs);
  10. Set<String> optionNames = args.getOptionNames();// 获取key-vlue形式值的key
  11. for (String optionName : optionNames) {
  12. // 获取获取key-vlue的值
  13. System.out.println(optionName + ":" + args.getOptionValues(optionName));
  14. }
  15. System.out.println(">>>>>>>>>>>>>>>MyApplicationRunner01结束>>>>>>>>>>>>>>>>");
  16. }
  17. }

---

  1. sourceArgs:[--name=sxz, --age=2, hello, word]
  2. nonOptionArgs:[hello, word]
  3. name:[sxz]
  4. age:[2]
  5. >>>>>>>>>>>>>>>MyApplicationRunner01结束>>>>>>>>>>>>>>>>

---

★扩展:args.getNonOptionArgs(); // 获取没有key的值   ===END

executeLocalJobs(JobParameters jobParameters) 

  1. private void executeLocalJobs(JobParameters jobParameters) throws JobExecutionException {
  2. for (Job job : this.jobs) {
  3. if (StringUtils.hasText(this.jobNames)) {
  4. String[] jobsToRun = this.jobNames.split(",");
  5. if (!PatternMatchUtils.simpleMatch(jobsToRun, job.getName())) {
  6. logger.debug(LogMessage.format("Skipped job: %s", job.getName()));
  7. continue;
  8. }
  9. }
  10. execute(job, jobParameters);
  11. }
  12. }

----

execute(Job job, JobParameters jobParameters)

先执行第四行,(取得、设定Parameters的值 (run.id))

后面回来,接着执行第5行。

  1. protected void execute(Job job, JobParameters jobParameters)
  2. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
  3. JobParametersInvalidException, JobParametersNotFoundException {
  4. JobParameters parameters = getNextJobParameters(job, jobParameters);
  5. JobExecution execution = this.jobLauncher.run(job, parameters);
  6. if (this.publisher != null) {
  7. this.publisher.publishEvent(new JobExecutionEvent(execution));
  8. }
  9. }

----

JobParameters getNextJobParameters(Job job, JobParameters jobParameters) 

下面的9行 执行

  1. private JobParameters getNextJobParameters(Job job, JobParameters jobParameters) {
  2. if (this.jobRepository != null && this.jobRepository.isJobInstanceExists(job.getName(), jobParameters)) {
  3. return getNextJobParametersForExisting(job, jobParameters);
  4. }
  5. if (job.getJobParametersIncrementer() == null) {
  6. return jobParameters;
  7. }
  8. JobParameters nextParameters = new JobParametersBuilder(jobParameters, this.jobExplorer)
  9. .getNextJobParameters(job).toJobParameters();
  10. return merge(nextParameters, jobParameters);
  11. }

3.JobParametersBuilder.java [ spring-batch-core-xxx.jar] 

  1. public class CommandLineJobRunner {
  2. public class SimpleJobOperator implements JobOperator, InitializingBean {
  3. public class JobLauncherApplicationRunner implements ApplicationRunner, Ordered, ApplicationEventPublisherAware {

getNextJobParameters(Job job)

★★★★★★★关于参数  parameters中的 【所有】参数的取得 ★★★★★★★

下面的15行是重点  

  1. JobExecution previousExecution =
  2. this.jobExplorer.getLastJobExecution(lastInstance);

     根据 上次的运行结果,获取 参数的值

      (具体:

              根据JobName,从【 batch_job_instance】 表中获取数据,

               这个表中有,job_instance_id, version,  job_name , job_key 字段

               因为有 job_name , 即使多个job 同时使用这一张表,

                也可以取得, 对应 jobname的 上一次的  job_instance_id

下面的21行, 使参数【run.id】的值加 1

  1. nextParameters = incrementer.getNext(
  2. previousExecution.getJobParameters());

===

  1. public JobParametersBuilder getNextJobParameters(Job job) {
  2. Assert.state(this.jobExplorer != null, "A JobExplorer is required to get next job parameters");
  3. Assert.notNull(job, "Job must not be null");
  4. Assert.notNull(job.getJobParametersIncrementer(), "No job parameters incrementer found for job=" + job.getName());
  5. String name = job.getName();
  6. JobParameters nextParameters;
  7. JobInstance lastInstance = this.jobExplorer.getLastJobInstance(name);
  8. JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
  9. if (lastInstance == null) {
  10. // Start from a completely clean sheet
  11. nextParameters = incrementer.getNext(new JobParameters());
  12. }
  13. else {
  14. JobExecution previousExecution = this.jobExplorer.getLastJobExecution(lastInstance);
  15. if (previousExecution == null) {
  16. // Normally this will not happen - an instance exists with no executions
  17. nextParameters = incrementer.getNext(new JobParameters());
  18. }
  19. else {
  20. nextParameters = incrementer.getNext(previousExecution.getJobParameters());
  21. }
  22. }
  23. // start with parameters from the incrementer
  24. Map<String, JobParameter> nextParametersMap = new HashMap<>(nextParameters.getParameters());
  25. // append new parameters (overriding those with the same key)
  26. nextParametersMap.putAll(this.parameterMap);
  27. this.parameterMap = nextParametersMap;
  28. return this;
  29. }

----

4.RunIdIncrementer.java   [ spring-boot-core-xxx.jar] 

★★★取得已经存在的run.id、加1处理,不存在的话,初始值1★★★

getNext(@Nullable JobParameters parameters) {

  1. public class RunIdIncrementer implements JobParametersIncrementer {
  2. private static String RUN_ID_KEY = "run.id";
  3. private String key = RUN_ID_KEY;
  4. /**
  5. * The name of the run id in the job parameters. Defaults to "run.id".
  6. *
  7. * @param key the key to set
  8. */
  9. public void setKey(String key) {
  10. this.key = key;
  11. }
  12. /**
  13. * Increment the run.id parameter (starting with 1).
  14. *
  15. * @param parameters the previous job parameters
  16. * @return the next job parameters with an incremented (or initialized) run.id
  17. * @throws IllegalArgumentException if the previous value of run.id is invalid
  18. */
  19. @Override
  20. public JobParameters getNext(@Nullable JobParameters parameters) {
  21. JobParameters params = (parameters == null) ? new JobParameters() : parameters;
  22. JobParameter runIdParameter = params.getParameters().get(this.key);
  23. long id = 1;
  24. if (runIdParameter != null) {
  25. try {
  26. id = Long.parseLong(runIdParameter.getValue().toString()) + 1;
  27. }
  28. catch (NumberFormatException exception) {
  29. throw new IllegalArgumentException("Invalid value for parameter "
  30. + this.key, exception);
  31. }
  32. }
  33. return new JobParametersBuilder(params).addLong(this.key, id).toJobParameters();
  34. }
  35. }

--

2.JobLauncherApplicationRunner.java(继续执行) [ spring-boot-autoconfigure-xxx.jar]

★★★关于参数  parameters中的 run.id  ★★★

第4行执行的时候,仅仅是把 run.id 加1

也就是说,如果上一次什么都没有,或者只是run.id那么,这次 就只是run.id。

如果上一次还有一些其它的值,比如下面这些

parameters: [{-spring.config.location=/xxx/xxx/xxx/application.xml, -spring.profiles.active=prod, run.id=123, -spring.batch.job.names=xxxxx}]

那么本次执行时,还会附带上这些参数

下面的5行执行  (【重要】 使用上面,4行处理中,生成的parameters !!!)

  1. protected void execute(Job job, JobParameters jobParameters)
  2. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
  3. JobParametersInvalidException, JobParametersNotFoundException {
  4. JobParameters parameters = getNextJobParameters(job, jobParameters);
  5. JobExecution execution = this.jobLauncher.run(job, parameters);
  6. if (this.publisher != null) {
  7. this.publisher.publishEvent(new JobExecutionEvent(execution));
  8. }
  9. }

---

5.SimpleJobLauncher.java

run(final Job job, final JobParameters jobParameters)

下面的47行是重点

下面的56行会显示log信息  (可以显示 【所有的】 参数 信息 !!! ) 

【这里的Log参数,与Batch启动时,传入的参数无关,与上一次的参数有关】 

o.s.b.c.SimpleJobLauncher Job: [Simple:[name=xxxxxxx]] completed with the following parameters: [{-spring.config.location=/xxx/xxx/xxx/application.xml, -spring.profiles.active=prod, run.id=123, -spring.batch.job.names=xxxxx}]

====

  1. public class SimpleJobLauncher implements JobLauncher, InitializingBean {
  2. 。。。。。。。。
  3. @Override
  4. public JobExecution run(final Job job, final JobParameters jobParameters)
  5. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException,
  6. JobParametersInvalidException {
  7. Assert.notNull(job, "The Job must not be null.");
  8. Assert.notNull(jobParameters, "The JobParameters must not be null.");
  9. final JobExecution jobExecution;
  10. JobExecution lastExecution = jobRepository.getLastJobExecution(job.getName(), jobParameters);
  11. if (lastExecution != null) {
  12. if (!job.isRestartable()) {
  13. throw new JobRestartException("JobInstance already exists and is not restartable");
  14. }
  15. /*
  16. * validate here if it has stepExecutions that are UNKNOWN, STARTING, STARTED and STOPPING
  17. * retrieve the previous execution and check
  18. */
  19. for (StepExecution execution : lastExecution.getStepExecutions()) {
  20. BatchStatus status = execution.getStatus();
  21. if (status.isRunning() || status == BatchStatus.STOPPING) {
  22. throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: "
  23. + lastExecution);
  24. } else if (status == BatchStatus.UNKNOWN) {
  25. throw new JobRestartException(
  26. "Cannot restart step [" + execution.getStepName() + "] from UNKNOWN status. "
  27. + "The last execution ended with a failure that could not be rolled back, "
  28. + "so it may be dangerous to proceed. Manual intervention is probably necessary.");
  29. }
  30. }
  31. }
  32. // Check the validity of the parameters before doing creating anything
  33. // in the repository...
  34. job.getJobParametersValidator().validate(jobParameters);
  35. /*
  36. * There is a very small probability that a non-restartable job can be
  37. * restarted, but only if another process or thread manages to launch
  38. * <i>and</i> fail a job execution for this instance between the last
  39. * assertion and the next method returning successfully.
  40. */
  41. jobExecution = jobRepository.createJobExecution(job.getName(), jobParameters);
  42. try {
  43. taskExecutor.execute(new Runnable() {
  44. @Override
  45. public void run() {
  46. try {
  47. if (logger.isInfoEnabled()) {
  48. logger.info("Job: [" + job + "] launched with the following parameters: [" + jobParameters
  49. + "]");
  50. }
  51. job.execute(jobExecution);
  52. if (logger.isInfoEnabled()) {
  53. Duration jobExecutionDuration = BatchMetrics.calculateDuration(jobExecution.getStartTime(), jobExecution.getEndTime());
  54. logger.info("Job: [" + job + "] completed with the following parameters: [" + jobParameters
  55. + "] and the following status: [" + jobExecution.getStatus() + "]"
  56. + (jobExecutionDuration == null ? "" : " in " + BatchMetrics.formatDuration(jobExecutionDuration)));
  57. }
  58. }
  59. catch (Throwable t) {
  60. if (logger.isInfoEnabled()) {
  61. logger.info("Job: [" + job
  62. + "] failed unexpectedly and fatally with the following parameters: [" + jobParameters
  63. + "]", t);
  64. }
  65. rethrow(t);
  66. }
  67. }
  68. private void rethrow(Throwable t) {
  69. if (t instanceof RuntimeException) {
  70. throw (RuntimeException) t;
  71. }
  72. else if (t instanceof Error) {
  73. throw (Error) t;
  74. }
  75. throw new IllegalStateException(t);
  76. }
  77. });
  78. }
  79. catch (TaskRejectedException e) {
  80. jobExecution.upgradeStatus(BatchStatus.FAILED);
  81. if (jobExecution.getExitStatus().equals(ExitStatus.UNKNOWN)) {
  82. jobExecution.setExitStatus(ExitStatus.FAILED.addExitDescription(e));
  83. }
  84. jobRepository.update(jobExecution);
  85. }
  86. return jobExecution;
  87. }

6.SimpleJobRepository.java [30行]

createJobExecution(String jobName, JobParameters jobParameters)

★★★本次整理原因★★★由于【run.id】对应的值过小,出现行下面9行(大段代码26行)的如下错误

  1. public class SimpleJobRepository implements JobRepository {
  2. .......
  3. @Override
  4. public JobExecution createJobExecution(String jobName, JobParameters jobParameters)
  5. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
  6. Assert.notNull(jobName, "Job name must not be null.");
  7. Assert.notNull(jobParameters, "JobParameters must not be null.");
  8. /*
  9. * Find all jobs matching the runtime information.
  10. *
  11. * If this method is transactional, and the isolation level is
  12. * REPEATABLE_READ or better, another launcher trying to start the same
  13. * job in another thread or process will block until this transaction
  14. * has finished.
  15. */
  16. JobInstance jobInstance = jobInstanceDao.getJobInstance(jobName, jobParameters);
  17. ExecutionContext executionContext;
  18. // existing job instance found
  19. if (jobInstance != null) {
  20. List<JobExecution> executions = jobExecutionDao.findJobExecutions(jobInstance);
  21. if (executions.isEmpty()) {
  22. throw new IllegalStateException("Cannot find any job execution for job instance: " + jobInstance);
  23. }
  24. // check for running executions and find the last started

JobInstance jobInstance = this.jobInstanceDao.getJobInstance(jobName, jobParameters);

7.JdbcJobInstanceDao.java  9行

getJobInstance(String jobName, JobParameters jobParameters)

下面的9行,15行是重点

   ・9行:生成 JOB_KEY  (根据 JobParameters  的值来生成) 

  ★★  ★★  ★★ 如果生成了和以前 (同JobName)重复的值 ,就凉凉了,系统一定会报错  ★★  ★★  ★★ 

START ============ START

		String jobKey = jobKeyGenerator.generateKey(jobParameters);

7.1 DefaultJobKeyGenerator.java

    下面17行中, 对参数进行了筛选 

if(jobParameter.isIdentifying()) {

   identify 英 [aɪˈdɛntɪˌfaɪ]  识别;认出;辨认;确认;确定

   这个字段来源于,batch_job_execution_params 表中的【identifying】字段。

    如果只有run.id对应的这个字段为【Y】,那么

     即使有多个参数,下面32行中, 变量【sringBuffer】的值是【run.id=xxx】

  1. public class DefaultJobKeyGenerator implements JobKeyGenerator<JobParameters> {
  2. /**
  3. * Generates the job key to be used based on the {@link JobParameters} instance
  4. * provided.
  5. */
  6. @Override
  7. public String generateKey(JobParameters source) {
  8. Assert.notNull(source, "source must not be null");
  9. Map<String, JobParameter> props = source.getParameters();
  10. StringBuilder stringBuffer = new StringBuilder();
  11. List<String> keys = new ArrayList<>(props.keySet());
  12. Collections.sort(keys);
  13. for (String key : keys) {
  14. JobParameter jobParameter = props.get(key);
  15. if(jobParameter.isIdentifying()) {
  16. String value = jobParameter.getValue()==null ? "" : jobParameter.toString();
  17. stringBuffer.append(key).append("=").append(value).append(";");
  18. }
  19. }
  20. MessageDigest digest;
  21. try {
  22. digest = MessageDigest.getInstance("MD5");
  23. } catch (NoSuchAlgorithmException e) {
  24. throw new IllegalStateException(
  25. "MD5 algorithm not available. Fatal (should be in the JDK).");
  26. }
  27. try {
  28. byte[] bytes = digest.digest(stringBuffer.toString().getBytes(
  29. "UTF-8"));
  30. return String.format("%032x", new BigInteger(1, bytes));
  31. } catch (UnsupportedEncodingException e) {
  32. throw new IllegalStateException(
  33. "UTF-8 encoding not available. Fatal (should be in the JDK).");
  34. }
  35. }
  36. }

  END ============  END

7.JdbcJobInstanceDao.java  15行

・15行:使用JOB_NAME 和 JOB_KEY (9行生成) 在 【BATCH_JOB_INSTANCE】表中查询。

SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?

           ・正常情况是不应该查询到数据的,因为每次 JobParameters  中, 【run.id】的值都是不同的

   ★★★↓出错根本原因(Cannot find any job execution for job instance: )★★★

           ・之所以会出错,是因为【BATCH_JOB_EXECUTION_PARAMS】表达数据被删除了,造成【run.id】的発番出现了问题。 重复使用了以前的值。 

  1. public class JdbcJobInstanceDao extends AbstractJdbcBatchMetadataDao implements JobInstanceDao, InitializingBean {
  2. 。。。。。。。
  3. @Nullable
  4. public JobInstance getJobInstance(String jobName, JobParameters jobParameters) {
  5. Assert.notNull(jobName, "Job name must not be null.");
  6. Assert.notNull(jobParameters, "JobParameters must not be null.");
  7. String jobKey = this.jobKeyGenerator.generateKey(jobParameters);
  8. RowMapper<JobInstance> rowMapper = new JobInstanceRowMapper(this);
  9. List instances;
  10. if (StringUtils.hasLength(jobKey)) {
  11. instances = this.getJdbcTemplate()
  12. .query(this.getQuery(
  13. "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?"),
  14. rowMapper, new Object[]{jobName, jobKey});
  15. } else {
  16. instances = this.getJdbcTemplate()
  17. .query(this.getQuery(
  18. "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? and (JOB_KEY = ? OR JOB_KEY is NULL)"),
  19. rowMapper, new Object[]{jobName, jobKey});
  20. }
  21. if (instances.isEmpty()) {
  22. return null;
  23. } else {
  24. Assert.state(instances.size() == 1, "instance count must be 1 but was " + instances.size());
  25. return (JobInstance) instances.get(0);
  26. }
  27. }

6.SimpleJobRepository.java (继续执行) [55行]

下面的55行是重点

  1. public class SimpleJobRepository implements JobRepository {
  2. .......
  3. @Override
  4. public JobExecution createJobExecution(String jobName, JobParameters jobParameters)
  5. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
  6. Assert.notNull(jobName, "Job name must not be null.");
  7. Assert.notNull(jobParameters, "JobParameters must not be null.");
  8. /*
  9. * Find all jobs matching the runtime information.
  10. *
  11. * If this method is transactional, and the isolation level is
  12. * REPEATABLE_READ or better, another launcher trying to start the same
  13. * job in another thread or process will block until this transaction
  14. * has finished.
  15. */
  16. JobInstance jobInstance = jobInstanceDao.getJobInstance(jobName, jobParameters);
  17. ExecutionContext executionContext;
  18. // existing job instance found
  19. if (jobInstance != null) {
  20. List<JobExecution> executions = jobExecutionDao.findJobExecutions(jobInstance);
  21. if (executions.isEmpty()) {
  22. throw new IllegalStateException("Cannot find any job execution for job instance: " + jobInstance);
  23. }
  24. // check for running executions and find the last started
  25. for (JobExecution execution : executions) {
  26. if (execution.isRunning() || execution.isStopping()) {
  27. throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: "
  28. + jobInstance);
  29. }
  30. BatchStatus status = execution.getStatus();
  31. if (status == BatchStatus.UNKNOWN) {
  32. throw new JobRestartException("Cannot restart job from UNKNOWN status. "
  33. + "The last execution ended with a failure that could not be rolled back, "
  34. + "so it may be dangerous to proceed. Manual intervention is probably necessary.");
  35. }
  36. if (execution.getJobParameters().getParameters().size() > 0 && (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED)) {
  37. throw new JobInstanceAlreadyCompleteException(
  38. "A job instance already exists and is complete for parameters=" + jobParameters
  39. + ". If you want to run this job again, change the parameters.");
  40. }
  41. }
  42. executionContext = ecDao.getExecutionContext(jobExecutionDao.getLastJobExecution(jobInstance));
  43. }
  44. else {
  45. // no job found, create one
  46. jobInstance = jobInstanceDao.createJobInstance(jobName, jobParameters);
  47. executionContext = new ExecutionContext();
  48. }
  49. JobExecution jobExecution = new JobExecution(jobInstance, jobParameters, null);
  50. jobExecution.setExecutionContext(executionContext);
  51. jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
  52. // Save the JobExecution so that it picks up an ID (useful for clients
  53. // monitoring asynchronous executions):
  54. jobExecutionDao.saveJobExecution(jobExecution);
  55. ecDao.saveExecutionContext(jobExecution);
  56. return jobExecution;
  57. }

8.JdbcJobInstanceDao.java

createJobInstance(String jobName, JobParameters jobParameters) {

  1. public class JdbcJobInstanceDao extends AbstractJdbcBatchMetadataDao implements
  2. JobInstanceDao, InitializingBean {
  3. private static final String STAR_WILDCARD = "*";
  4. private static final String SQL_WILDCARD = "%";
  5. private static final String CREATE_JOB_INSTANCE = "INSERT into %PREFIX%JOB_INSTANCE(JOB_INSTANCE_ID, JOB_NAME, JOB_KEY, VERSION)"
  6. + " values (?, ?, ?, ?)";
  7. private static final String FIND_JOBS_WITH_NAME = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ?";
  8. private static final String FIND_JOBS_WITH_KEY = FIND_JOBS_WITH_NAME
  9. 。。。。。。。
  10. @Override
  11. public JobInstance createJobInstance(String jobName,
  12. JobParameters jobParameters) {
  13. Assert.notNull(jobName, "Job name must not be null.");
  14. Assert.notNull(jobParameters, "JobParameters must not be null.");
  15. Assert.state(getJobInstance(jobName, jobParameters) == null,
  16. "JobInstance must not already exist");
  17. Long jobId = jobIncrementer.nextLongValue();
  18. JobInstance jobInstance = new JobInstance(jobId, jobName);
  19. jobInstance.incrementVersion();
  20. Object[] parameters = new Object[] { jobId, jobName,
  21. jobKeyGenerator.generateKey(jobParameters), jobInstance.getVersion() };
  22. getJdbcTemplate().update(
  23. getQuery(CREATE_JOB_INSTANCE),
  24. parameters,
  25. new int[] { Types.BIGINT, Types.VARCHAR, Types.VARCHAR,
  26. Types.INTEGER });
  27. return jobInstance;
  28. }
  29. 。。。。。。。

===

6.SimpleJobRepository.java (继续执行) [65行]

createJobExecution(String jobName, JobParameters jobParameters)

下面的65行是重点

  1. public class SimpleJobRepository implements JobRepository {
  2. .......
  3. @Override
  4. public JobExecution createJobExecution(String jobName, JobParameters jobParameters)
  5. throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException {
  6. Assert.notNull(jobName, "Job name must not be null.");
  7. Assert.notNull(jobParameters, "JobParameters must not be null.");
  8. /*
  9. * Find all jobs matching the runtime information.
  10. *
  11. * If this method is transactional, and the isolation level is
  12. * REPEATABLE_READ or better, another launcher trying to start the same
  13. * job in another thread or process will block until this transaction
  14. * has finished.
  15. */
  16. JobInstance jobInstance = jobInstanceDao.getJobInstance(jobName, jobParameters);
  17. ExecutionContext executionContext;
  18. // existing job instance found
  19. if (jobInstance != null) {
  20. List<JobExecution> executions = jobExecutionDao.findJobExecutions(jobInstance);
  21. if (executions.isEmpty()) {
  22. throw new IllegalStateException("Cannot find any job execution for job instance: " + jobInstance);
  23. }
  24. // check for running executions and find the last started
  25. for (JobExecution execution : executions) {
  26. if (execution.isRunning() || execution.isStopping()) {
  27. throw new JobExecutionAlreadyRunningException("A job execution for this job is already running: "
  28. + jobInstance);
  29. }
  30. BatchStatus status = execution.getStatus();
  31. if (status == BatchStatus.UNKNOWN) {
  32. throw new JobRestartException("Cannot restart job from UNKNOWN status. "
  33. + "The last execution ended with a failure that could not be rolled back, "
  34. + "so it may be dangerous to proceed. Manual intervention is probably necessary.");
  35. }
  36. if (execution.getJobParameters().getParameters().size() > 0 && (status == BatchStatus.COMPLETED || status == BatchStatus.ABANDONED)) {
  37. throw new JobInstanceAlreadyCompleteException(
  38. "A job instance already exists and is complete for parameters=" + jobParameters
  39. + ". If you want to run this job again, change the parameters.");
  40. }
  41. }
  42. executionContext = ecDao.getExecutionContext(jobExecutionDao.getLastJobExecution(jobInstance));
  43. }
  44. else {
  45. // no job found, create one
  46. jobInstance = jobInstanceDao.createJobInstance(jobName, jobParameters);
  47. executionContext = new ExecutionContext();
  48. }
  49. JobExecution jobExecution = new JobExecution(jobInstance, jobParameters, null);
  50. jobExecution.setExecutionContext(executionContext);
  51. jobExecution.setLastUpdated(new Date(System.currentTimeMillis()));
  52. // Save the JobExecution so that it picks up an ID (useful for clients
  53. // monitoring asynchronous executions):
  54. jobExecutionDao.saveJobExecution(jobExecution);
  55. ecDao.saveExecutionContext(jobExecution);
  56. return jobExecution;
  57. }

--

9.JdbcJobExecutionDao.java

saveJobExecution(JobExecution jobExecution) {

下面的 4, 23行,是重点  // 向【BATCH_JOB_EXECUTION】表中插入数据

下面的16行,是重点  // 第16行执行之后,Job_Execution_ID 才有值     //  jobExecution.setId(jobExecutionIncrementer.nextLongValue());

下面的28行,是重点  // 28行的时候,首次传递了Job_Execution_ID

  1. public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements JobExecutionDao, InitializingBean {
  2. 。。。。。。。
  3. private static final String SAVE_JOB_EXECUTION = "INSERT into %PREFIX%JOB_EXECUTION(JOB_EXECUTION_ID, JOB_INSTANCE_ID, START_TIME, "
  4. + "END_TIME, STATUS, EXIT_CODE, EXIT_MESSAGE, VERSION, CREATE_TIME, LAST_UPDATED, JOB_CONFIGURATION_LOCATION) values (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)";
  5. 。。。。。。。
  6. @Override
  7. public void saveJobExecution(JobExecution jobExecution) {
  8. validateJobExecution(jobExecution);
  9. jobExecution.incrementVersion();
  10. jobExecution.setId(jobExecutionIncrementer.nextLongValue());
  11. Object[] parameters = new Object[] { jobExecution.getId(), jobExecution.getJobId(),
  12. jobExecution.getStartTime(), jobExecution.getEndTime(), jobExecution.getStatus().toString(),
  13. jobExecution.getExitStatus().getExitCode(), jobExecution.getExitStatus().getExitDescription(),
  14. jobExecution.getVersion(), jobExecution.getCreateTime(), jobExecution.getLastUpdated(),
  15. jobExecution.getJobConfigurationName() };
  16. getJdbcTemplate().update(
  17. getQuery(SAVE_JOB_EXECUTION),
  18. parameters,
  19. new int[] { Types.BIGINT, Types.BIGINT, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR,
  20. Types.VARCHAR, Types.VARCHAR, Types.INTEGER, Types.TIMESTAMP, Types.TIMESTAMP, Types.VARCHAR });
  21. insertJobParameters(jobExecution.getId(), jobExecution.getJobParameters());
  22. }

insertParameter(Long executionId, ParameterType type, String key, Object value, boolean identifying) {

下面的55行,将数据插入DB的向【BATCH_JOB_EXECUTION_PARAMS】表中插入数据

  1. public class JdbcJobExecutionDao extends AbstractJdbcBatchMetadataDao implements JobExecutionDao, InitializingBean {
  2. 。。。。。。。
  3. private static final String FIND_PARAMS_FROM_ID = "SELECT JOB_EXECUTION_ID, KEY_NAME, TYPE_CD, "
  4. + "STRING_VAL, DATE_VAL, LONG_VAL, DOUBLE_VAL, IDENTIFYING from %PREFIX%JOB_EXECUTION_PARAMS where JOB_EXECUTION_ID = ?";
  5. private static final String CREATE_JOB_PARAMETERS = "INSERT into %PREFIX%JOB_EXECUTION_PARAMS(JOB_EXECUTION_ID, KEY_NAME, TYPE_CD, "
  6. + "STRING_VAL, DATE_VAL, LONG_VAL, DOUBLE_VAL, IDENTIFYING) values (?, ?, ?, ?, ?, ?, ?, ?)";
  7. 。。。。。。。
  8. /**
  9. * Convenience method that inserts all parameters from the provided
  10. * JobParameters.
  11. *
  12. */
  13. private void insertJobParameters(Long executionId, JobParameters jobParameters) {
  14. for (Entry<String, JobParameter> entry : jobParameters.getParameters()
  15. .entrySet()) {
  16. JobParameter jobParameter = entry.getValue();
  17. insertParameter(executionId, jobParameter.getType(), entry.getKey(),
  18. jobParameter.getValue(), jobParameter.isIdentifying());
  19. }
  20. }
  21. /**
  22. * Convenience method that inserts an individual records into the
  23. * JobParameters table.
  24. */
  25. private void insertParameter(Long executionId, ParameterType type, String key,
  26. Object value, boolean identifying) {
  27. Object[] args = new Object[0];
  28. int[] argTypes = new int[] { Types.BIGINT, Types.VARCHAR,
  29. Types.VARCHAR, Types.VARCHAR, Types.TIMESTAMP, Types.BIGINT,
  30. Types.DOUBLE, Types.CHAR };
  31. String identifyingFlag = identifying? "Y":"N";
  32. if (type == ParameterType.STRING) {
  33. args = new Object[] { executionId, key, type, value, new Timestamp(0L),
  34. 0L, 0D, identifyingFlag};
  35. } else if (type == ParameterType.LONG) {
  36. args = new Object[] { executionId, key, type, "", new Timestamp(0L),
  37. value, new Double(0), identifyingFlag};
  38. } else if (type == ParameterType.DOUBLE) {
  39. args = new Object[] { executionId, key, type, "", new Timestamp(0L), 0L,
  40. value, identifyingFlag};
  41. } else if (type == ParameterType.DATE) {
  42. args = new Object[] { executionId, key, type, "", value, 0L, 0D, identifyingFlag};
  43. }
  44. getJdbcTemplate().update(getQuery(CREATE_JOB_PARAMETERS), args, argTypes);
  45. }
  46. 。。。。。。。

---

五.模拟 生成 JOB_KEY  的代码

  1. package com.sxz.common.utils;
  2. import java.io.UnsupportedEncodingException;
  3. import java.math.BigInteger;
  4. import java.security.MessageDigest;
  5. import java.security.NoSuchAlgorithmException;
  6. public class GetMD5Info {
  7. public static void main (String[] args) {
  8. // 结尾有分号,应该是想用分号来,分割开来多个参数
  9. // 具体参照 7.1 中的源码 19
  10. // stringBuffer.append(key).append("=").append(value).append(";");
  11. System.out.println(EncoderByMd5("run.id=3;"));
  12. }
  13. public static String EncoderByMd5(String str) {
  14. if (str == null) {
  15. return null;
  16. }
  17. String strMD5 = "";
  18. try {
  19. // 确定计算方法
  20. MessageDigest md5 = MessageDigest.getInstance("MD5");
  21. // 加密后的字符串
  22. byte[] bytes = md5.digest(str.getBytes("utf-8"));
  23. strMD5 = String.format("%032x", new BigInteger(1, bytes));
  24. } catch (NoSuchAlgorithmException | UnsupportedEncodingException e) {
  25. return null;
  26. }
  27. return strMD5;
  28. }
  29. }

---

a3364faf893276dea0caacefbf618db5

---

六.删除各表数据时,要按照顺序删除

因为有主外键,所有只能按照下面顺序,删除表中数据

  1. delete from BATCH_JOB_EXECUTION_PARAMS;
  2. delete from BATCH_STEP_EXECUTION_CONTEXT;
  3. delete from BATCH_JOB_EXECUTION_CONTEXT;
  4. delete from BATCH_STEP_EXECUTION;
  5. delete from BATCH_JOB_EXECUTION;
  6. delete from BATCH_JOB_INSTANCE;

====

七.问题解决方法

1.删除【BATCH_JOB_INSTANCE】表中,对应的Log中的instanceid的记录

Cannot find any job execution for job instance: id= XXXX

2.再手动运行一下SpringBatch的JOB

    同时,保留,刚刚运行完JOB后,SpringBatch表中的信息。

    尤其时【BATCH_JOB_EXECUTION_PARAMS】表

    因为这里面有, run.id

3.获得合适的run.id的值。 (保证在【BATCH_JOB_INSTANCE】表中,没有重复的值。)

          (不过,不同的Jobname,重复也没有关系)

4.更新2中生成的【BATCH_JOB_EXECUTION_PARAMS】表中记录的run.id的值。

5.如果还有其它参数信息,一起补足。(下一次的参数信息,根据上一次而来。)

6.再次多次,连续执行Job,确认不再出错。

---

八.扩展:更多Java知识

Java8新特性学习_001_(Lambda表达式,函数式接口,方法引用,Stream类,Optional类)_sun0322的博客-CSDN博客

===

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/weixin_40725706/article/detail/631020
推荐阅读
相关标签
  

闽ICP备14008679号