spring-batch
ジョブを作成したいのですが、データベースを永続化せずに実行したいです。残念ながら、スプリングバッチでは、ジョブサイクルを何らかの方法でデータベースにmetadata
ob書き込む必要があるため、少なくとも何らかの種類のdbをtransactionmanagerおよびentitymanagerで提供する必要があります。
メタデータを防止し、txmanagersおよびデータベースから独立して実行することは可能ですか?
更新:
ERROR org.springframework.batch.core.job.AbstractJob: Encountered fatal error executing job
Java.lang.NullPointerException
at org.springframework.batch.core.repository.dao.MapJobExecutionDao.synchronizeStatus(MapJobExecutionDao.Java:158) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.batch.core.repository.support.SimpleJobRepository.update(SimpleJobRepository.Java:161) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor$1.proceedWithInvocation(TransactionInterceptor.Java:98) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.Java:262) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.Java:95) ~[spring-tx-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at com.Sun.proxy.$Proxy134.update(Unknown Source) ~[?:?]
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.Java:127) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) ~[spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at com.Sun.proxy.$Proxy134.update(Unknown Source) ~[?:?]
at org.springframework.batch.core.job.AbstractJob.updateStatus(AbstractJob.Java:416) ~[spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.Java:299) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.Java:135) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.Java:50) [spring-core-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.Java:128) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at Sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.7.0_51]
at Sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.Java:57) ~[?:1.7.0_51]
at Sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.Java:43) ~[?:1.7.0_51]
at Java.lang.reflect.Method.invoke(Method.Java:606) ~[?:1.7.0_51]
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.Java:317) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.Java:190) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:157) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.Java:127) [spring-batch-core-3.0.1.RELEASE.jar:3.0.1.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.Java:179) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.Java:207) [spring-aop-4.0.6.RELEASE.jar:4.0.6.RELEASE]
at com.Sun.proxy.$Proxy50.run(Unknown Source) [?:?]
ソリューションが機能しなくなったため、私は自分の質問に戻りました。 spring-batch-1.5.3以降、次のように使用します。
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
...
@Bean
public PlatformTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
}
バッチ構成のデータソースなしで構成を作成するだけです。
@Configuration
@EnableAutoConfiguration
@EnableBatchProcessing
public class BatchConfiguration extends DefaultBatchConfigurer {
@Override
public void setDataSource(DataSource dataSource) {
// override to do not set datasource even if a datasource exist.
// initialize will use a Map based JobRepository (instead of database)
}
}
メモリマップベースの実装でJobRepositoryとJobExplorerを初期化します。 https://github.com/spring-projects/spring-batch/blob/342d27bc1ed83312bdcd9c0cb30510f4c469e47d/spring-batch-core/src/main/Java/org/springframework/batch/core/configuration/annotation/DefaultBatchConfigurer。 Java#L84
また、スプリングブートで自動構成されている場合でも、実稼働データソースとして使用できます。
データベースの永続性なしで実行したい
MapJobRepositoryFactoryBean
および ResourcelessTransactionManager
を使用できます
サンプル構成:
<bean id="transactionManager"
class="org.springframework.batch.support.transaction.ResourcelessTransactionManager" />
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.MapJobRepositoryFactoryBean">
<property name="transactionManager" ref="transactionManager" />
</bean>
<bean id="jobLauncher"
class="org.springframework.batch.core.launch.support.SimpleJobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
Spring 4.Xの場合、注釈ベースの構成は次のようになります。
@Bean
public PlatformTransactionManager getTransactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobRepository getJobRepo() {
return new MapJobRepositoryFactoryBean(getTransactionManager()).getObject();
}
@Brajの答えを微調整した後、私の作業構成は次のようになります。
@Bean
public ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public JobRepository jobRepository(ResourcelessTransactionManager transactionManager) throws Exception {
MapJobRepositoryFactoryBean mapJobRepositoryFactoryBean = new MapJobRepositoryFactoryBean(transactionManager);
mapJobRepositoryFactoryBean.setTransactionManager(transactionManager);
return mapJobRepositoryFactoryBean.getObject();
}
@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository);
return simpleJobLauncher;
}
ジョブのメタデータをデータベースに保存したくない場合、構成は次のようになります
@Configuration
public class InMemoryJobRepositoryConfiguration {
@Bean
public ResourcelessTransactionManager transactionManager() {
return new ResourcelessTransactionManager();
}
@Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(ResourcelessTransactionManager transactionManager)
throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean(transactionManager);
factory.afterPropertiesSet();
return factory;
}
@Bean
public JobRepository jobRepository(MapJobRepositoryFactoryBean repositoryFactory) throws Exception {
return repositoryFactory.getObject();
}
@Bean
public JobExplorer jobExplorer(MapJobRepositoryFactoryBean repositoryFactory) {
return new SimpleJobExplorer(repositoryFactory.getJobInstanceDao(), repositoryFactory.getJobExecutionDao(),
repositoryFactory.getStepExecutionDao(), repositoryFactory.getExecutionContextDao());
}
@Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
return launcher;
}
}
ジョブがビジネスデータをデータベースに読み書きする必要があり、データソースが次のように構成されている場合。
@Autowired
private DataSource dataSource;
spring batchは、そのデータソースを使用して内部スキーマ(BATCH_ *テーブルとシーケンス)を作成します。これを防ぐには、application.propertiesでspring.batch.initializer.enabled=false
フラグを設定します。
@ Braj-sの応答に加えて、バッチ自動構成を除外する必要がありました:@SpringBootApplication(exclude = {BatchAutoConfiguration.class})
それ以外では機能していませんでした。これには、Spring Bootアプリケーションが含まれます
上記のすべてのソリューションを試しましたが、私の春のバッチジョブにはマルチスレッドなどの高度な機能があるため、特定のシナリオでは機能しません。データベースが必要です。だから、ここに私が問題を解決するためにしたことです:
@Configuration
public class FakeBatchConfig implements BatchConfigurer {
PlatformTransactionManager transactionManager;
JobRepository jobRepository;
JobLauncher jobLauncher;
JobExplorer jobExplorer;
@Override
public JobRepository getJobRepository() {
return jobRepository;
}
@Override
public PlatformTransactionManager getTransactionManager() {
return transactionManager;
}
@Override
public JobLauncher getJobLauncher() {
return jobLauncher;
}
@Override
public JobExplorer getJobExplorer() {
return jobExplorer;
}
@PostConstruct
void initialize() throws Exception {
if (this.transactionManager == null) {
this.transactionManager = new ResourcelessTransactionManager();
}
MapJobRepositoryFactoryBean jobRepositoryFactory = new MapJobRepositoryFactoryBean(this.transactionManager);
jobRepositoryFactory.afterPropertiesSet();
this.jobRepository = jobRepositoryFactory.getObject();
MapJobExplorerFactoryBean jobExplorerFactory = new MapJobExplorerFactoryBean(jobRepositoryFactory);
jobExplorerFactory.afterPropertiesSet();
this.jobExplorer = jobExplorerFactory.getObject();
this.jobLauncher = createJobLauncher();
}
private JobLauncher createJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(jobRepository);
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
}
提供されたすべての答えを読んだ後、私はそれを機能させました。 membersoundとAure77ソリューションを組み合わせて使用しました。 setDataSourceメソッドをオーバーライドする必要がないことがわかりました。 DefaultBatchConfigurerはPlatformTransactionManagerを自動的に処理し、DataSourceは必要ありません。 Spring boot 2.0.3.RELEASEを使用していることに注意してください。以下は私が使用した方法です
@SpringBootApplication(exclude = { DataSourceAutoConfiguration.class })
@EnableBatchProcessing
public class DemoApplication extends DefaultBatchConfigurer {
@Autowired
private JobBuilderFactory jobs;
@Autowired
private StepBuilderFactory steps;
@Bean
protected Tasklet tasklet() {
return new Tasklet() {
@Override
public RepeatStatus execute(StepContribution contribution, ChunkContext context) {
return RepeatStatus.FINISHED;
}
};
}
@Bean
public Job job() throws Exception {
return this.jobs.get("job").start(step1()).build();
}
@Bean
protected Step step1() throws Exception {
return this.steps.get("step1").tasklet(tasklet()).build();
}
public static void main(String[] args) throws Exception {
//System.exit(SpringApplication.exit(SpringApplication.run(DemoApplication.class, args)));
SpringApplication.run(DemoApplication.class, args);
}
}
最も簡単なのは、組み込みデータベースをクラスパスに追加することです。当然本番環境での使用は推奨されませんが、学習に使用する場合は時間を節約してください。
Pom.xmlに埋め込みH2データベース依存関係を追加します。
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
それで全部です。