Использование нескольких источников данных в Spring Batch Tasklet - PullRequest
0 голосов
/ 14 июля 2020

Я новичок в Spring Batch, и у меня возникает проблема при использовании нескольких источников данных в моем пакете.

Позвольте мне объяснить.

Я использую 2 базы данных на моем сервере с Spring Boot.

До сих пор все работало нормально с моей реализацией RoutingDataSource.

@Component("dataSource")
public class RoutingDataSource extends AbstractRoutingDataSource {

  @Autowired
  @Qualifier("datasourceA")
  DataSource datasourceA;

  @Autowired
  @Qualifier("datasourceB")
  DataSource datasourceB;

  @PostConstruct
  public void init() {
    setDefaultTargetDataSource(datasourceA);
    final Map<Object, Object> map = new HashMap<>();
    map.put(Database.A, datasourceA);
    map.put(Database.B, datasourceB);
    setTargetDataSources(map);
  }

  
  @Override
  protected Object determineCurrentLookupKey() {
    return DatabaseContextHolder.getDatabase();
  }
}

Для реализации требуется DatabaseContextHolder, вот он:

public class DatabaseContextHolder {
    private static final ThreadLocal<Database> contextHolder = new ThreadLocal<>();

    public static void setDatabase(final Database dbConnection) {
        contextHolder.set(dbConnection);
    }

    public static Database getDatabase() {
        return contextHolder.get();
    }
}

Когда Я получил запрос на свой сервер, у меня есть перехватчик basi c, который устанавливает текущую базу данных на основе некоторых входных данных, которые я имею в запросе. с помощью метода DatabaseContextHolder.setDatabase(db); Все отлично работает с моими настоящими контроллерами.

Все становится сложнее, когда я пытаюсь запустить задание с одним тасклетом.

Один из моих контроллеров запускает асинхронный режим c задача вроде этой.

@GetMapping("/batch")
public void startBatch() {
  return jobLauncher.run("myJob", new JobParameters());
}

@EnableBatchProcessing
@Configuration
public class MyBatch extends DefaultBatchConfigurer {


  @Autowired private JobBuilderFactory jobs;

  @Autowired private StepBuilderFactory steps;

  @Autowired private MyTasklet tasklet;

  @Bean
  public Job job(Step step) {
    return jobs.get("myJob").start(step).build();
  }

  @Bean
  protected Step registeredDeliveryTask() {
    return steps.get("myTask").tasklet(tasklet).build();
  }

  /** Overring the joblauncher get method to make it asynchornous */
  @Override
  public JobLauncher getJobLauncher() {
    try {
      SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
      jobLauncher.setJobRepository(super.getJobRepository());
      jobLauncher.setTaskExecutor(new SimpleAsyncTaskExecutor());
      jobLauncher.afterPropertiesSet();
      return jobLauncher;
    } catch (Exception e) {
      throw new BatchConfigurationException(e);
    }
  }
}

И мой тасклет:

@Component
public class MyTasklet implements Tasklet {

  @Autowired
  private UserRepository repository;

  @Override
  public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)throws Exception {

  //Do stuff with the repository.

  }

Но RoutingDataSource не работает, даже если я установил свой контекст перед запуском работы. Например, если я установил для своей базы данных значение B, репозиторий будет работать с базой данных A. Всегда выбирается источник данных по умолчанию. (из-за этой строки setDefaultTargetDataSource(datasourceA); )

Я попытался установить базу данных, передав значение в параметрах внутри тасклета, но все равно получил ту же проблему.

@GetMapping("/batch")
public void startBatch() {
  Map<String, JobParameter> parameters = new HashMap<>();
  parameters.put("database", new JobParameter(DatabaseContextHolder.getCircaDatabase().toString()));
  return jobLauncher.run("myJob", new JobParameters(parameters));
}
  @Override
  public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext)throws Exception {

    String database =
        chunkContext.getStepContext().getStepExecution().getJobParameters().getString("database");
    DatabaseContextHolder.setDatabase(Database.valueOf(database));
  //Do stuff with the repository.

  }

Мне кажется, проблема в том, что база данных была установлена ​​в другом потоке, потому что моя работа асинхронная. Таким образом, он не может получить набор базы данных перед запуском задания. Но пока найти решение не удалось.

С уважением

1 Ответ

0 голосов
/ 15 июля 2020

Ваш источник данных маршрутизации используется для метаданных Spring Batch, что означает, что репозиторий заданий будет взаимодействовать с другой базой данных в зависимости от потока, обрабатывающего запрос. Это не требуется для пакетных заданий. Вам необходимо настроить Spring Batch для работы с фиксированным источником данных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...