Java 带两个数据库的Spring批处理JPA块问题

Java 带两个数据库的Spring批处理JPA块问题,java,spring-boot,spring-data,spring-batch,spring-data-jpa,Java,Spring Boot,Spring Data,Spring Batch,Spring Data Jpa,我在使用两个带有JPA块处理的数据库创建spring批处理作业时遇到了一个问题。我有两个数据库: sourceDB:源数据 destinationDB:目标数据+Spring批处理元数据 Spring批处理读取并正确处理sourceDB中的数据,但当它写入destinationDB时,会出现以下异常: javax.persistence.TransactionRequiredException: no transaction is in progress at org.hiberna

我在使用两个带有JPA块处理的数据库创建spring批处理作业时遇到了一个问题。我有两个数据库:

  • sourceDB:源数据
  • destinationDB:目标数据+Spring批处理元数据
Spring批处理读取并正确处理sourceDB中的数据,但当它写入destinationDB时,会出现以下异常:

javax.persistence.TransactionRequiredException: no transaction is in progress
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.checkTransactionNeeded(AbstractEntityManagerImpl.java:1136) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1297) ~[hibernate-entitymanager-5.0.9.Final.jar:5.0.9.Final]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_71]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_71]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_71]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_71]
    at org.springframework.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:347) ~[spring-orm-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at com.sun.proxy.$Proxy56.flush(Unknown Source) ~[na:na]
    at org.springframework.batch.item.database.JpaItemWriter.write(JpaItemWriter.java:84) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.writeItems(SimpleChunkProcessor.java:175) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.doWrite(SimpleChunkProcessor.java:151) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.write(SimpleChunkProcessor.java:274) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.SimpleChunkProcessor.process(SimpleChunkProcessor.java:199) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.item.ChunkOrientedTasklet.execute(ChunkOrientedTasklet.java:75) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:406) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$ChunkTransactionCallback.doInTransaction(TaskletStep.java:330) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.transaction.support.TransactionTemplate.execute(TransactionTemplate.java:133) ~[spring-tx-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep$2.doInChunkContext(TaskletStep.java:271) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.scope.context.StepContextRepeatCallback.doInIteration(StepContextRepeatCallback.java:81) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.getNextResult(RepeatTemplate.java:374) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.executeInternal(RepeatTemplate.java:215) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.repeat.support.RepeatTemplate.iterate(RepeatTemplate.java:144) ~[spring-batch-infrastructure-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.tasklet.TaskletStep.doExecute(TaskletStep.java:257) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.step.AbstractStep.execute(AbstractStep.java:200) ~[spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.SimpleStepHandler.handleStep(SimpleStepHandler.java:148) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.flow.JobFlowExecutor.executeStep(JobFlowExecutor.java:64) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.flow.support.state.StepState.handle(StepState.java:67) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.flow.support.SimpleFlow.resume(SimpleFlow.java:169) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.flow.support.SimpleFlow.start(SimpleFlow.java:144) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.flow.FlowJob.doExecute(FlowJob.java:134) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.job.AbstractJob.execute(AbstractJob.java:306) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher$1.run(SimpleJobLauncher.java:135) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.core.task.SyncTaskExecutor.execute(SyncTaskExecutor.java:50) [spring-core-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.batch.core.launch.support.SimpleJobLauncher.run(SimpleJobLauncher.java:128) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_71]
    at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_71]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[na:1.8.0_71]
    at java.lang.reflect.Method.invoke(Unknown Source) ~[na:1.8.0_71]
    at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:333) [spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:190) [spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:157) [spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.batch.core.configuration.annotation.SimpleBatchConfiguration$PassthruAdvice.invoke(SimpleBatchConfiguration.java:127) [spring-batch-core-3.0.7.RELEASE.jar:3.0.7.RELEASE]
    at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179) [spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213) [spring-aop-4.3.2.RELEASE.jar:4.3.2.RELEASE]
    at com.sun.proxy.$Proxy63.run(Unknown Source) [na:na]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.execute(JobLauncherCommandLineRunner.java:216) [spring-boot-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.executeLocalJobs(JobLauncherCommandLineRunner.java:233) [spring-boot-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.launchJobFromProperties(JobLauncherCommandLineRunner.java:125) [spring-boot-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.autoconfigure.batch.JobLauncherCommandLineRunner.run(JobLauncherCommandLineRunner.java:119) [spring-boot-autoconfigure-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:798) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:782) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.afterRefresh(SpringApplication.java:769) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:314) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1185) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1174) [spring-boot-1.4.0.RELEASE.jar:1.4.0.RELEASE]
    at es.dmunozfer.example.batch.SpringBatchTwoDatabasesExampleApplication.main(SpringBatchTwoDatabasesExampleApplication.java:12) [classes/:na]
我正在使用Spring Boot 1.4
Spring Boot starter批处理
Spring Boot starter数据jpa
。我上传了一个简单的例子来说明GitHub中的错误

示例代码

SourceDatabaseConfig

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "sourceEntityManagerFactory", 
    transactionManagerRef = "sourceTransactionManager", 
    basePackages = "es.dmunozfer.example.batch.data.source")
public class SourceDatabaseConfig {

    @Bean(name = "sourceDatasource")
    @ConfigurationProperties(prefix = "datasource.source")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sourceEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("es.dmunozfer.example.batch.data.source");

        return factoryBean;
    }

    @Bean(name = "sourceTransactionManager")
    PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }
}
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "destinationEntityManagerFactory", 
    transactionManagerRef = "destinationTransactionManager", 
    basePackages = "es.dmunozfer.example.batch.data.destination")
public class DestinationDatabaseConfig {

    @Bean(name = "destinationDatasource")
    @ConfigurationProperties(prefix = "datasource.destination")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "destinationEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("es.dmunozfer.example.batch.data.destination");

        return factoryBean;
    }

    @Bean(name = "destinationTransactionManager")
    PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }
}
DestinationDatabaseConfig

@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "sourceEntityManagerFactory", 
    transactionManagerRef = "sourceTransactionManager", 
    basePackages = "es.dmunozfer.example.batch.data.source")
public class SourceDatabaseConfig {

    @Bean(name = "sourceDatasource")
    @ConfigurationProperties(prefix = "datasource.source")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "sourceEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("es.dmunozfer.example.batch.data.source");

        return factoryBean;
    }

    @Bean(name = "sourceTransactionManager")
    PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }
}
@Configuration
@EnableJpaRepositories(entityManagerFactoryRef = "destinationEntityManagerFactory", 
    transactionManagerRef = "destinationTransactionManager", 
    basePackages = "es.dmunozfer.example.batch.data.destination")
public class DestinationDatabaseConfig {

    @Bean(name = "destinationDatasource")
    @ConfigurationProperties(prefix = "datasource.destination")
    public DataSource dataSource() {
        return DataSourceBuilder.create().build();
    }

    @Bean(name = "destinationEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        HibernateJpaVendorAdapter jpaVendorAdapter = new HibernateJpaVendorAdapter();
        jpaVendorAdapter.setGenerateDdl(true);

        LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
        factoryBean.setDataSource(dataSource());
        factoryBean.setJpaVendorAdapter(jpaVendorAdapter);
        factoryBean.setPackagesToScan("es.dmunozfer.example.batch.data.destination");

        return factoryBean;
    }

    @Bean(name = "destinationTransactionManager")
    PlatformTransactionManager transactionManager() {
        return new JpaTransactionManager(entityManagerFactory().getObject());
    }
}
TwoDatabaseExampleJobConfiguration

@Configuration
@EnableAutoConfiguration
public class TwoDatabaseExampleJobConfiguration {

    @Autowired
    private JobBuilderFactory jobBuilderFactory;

    @Autowired
    @Qualifier("sourceEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean sourceEntityManagerFactory;

    @Autowired
    @Qualifier("destinationEntityManagerFactory")
    LocalContainerEntityManagerFactoryBean destinationEntityManagerFactory;

    @Bean
    public Step step1(StepBuilderFactory stepBuilderFactory, ItemReader<SourceEntity> reader,
                      ItemWriter<DestinationEntity> writer, ItemProcessor<SourceEntity, DestinationEntity> processor) {
        return stepBuilderFactory.get("step1")
                .<SourceEntity, DestinationEntity>chunk(100)
                .reader(reader)
                .processor(processor)
                .writer(writer)
                .build();
    }

    @Bean
    public Job job(Step step1) throws Exception {
        return jobBuilderFactory.get("twoDatabaseExampleJob")           
                .incrementer(new RunIdIncrementer())
                .flow(step1)
                .end()
                .build();
    }

    @Bean(destroyMethod="")
    public ItemReader<SourceEntity> reader() throws Exception {
        String jpqlQuery = "select se from SourceEntity se";

        JpaPagingItemReader<SourceEntity> reader = new JpaPagingItemReader<SourceEntity>();
        reader.setQueryString(jpqlQuery);
        reader.setEntityManagerFactory(sourceEntityManagerFactory.getObject());
        reader.setPageSize(50);
        reader.afterPropertiesSet();
        reader.setSaveState(true);

        return reader;
    }

    @Bean
    public ItemProcessor<SourceEntity, DestinationEntity> processor() {
        return new CustomItemProcessor();
    }

    @Bean
    public ItemWriter<DestinationEntity> writer() {
        JpaItemWriter<DestinationEntity> writer = new JpaItemWriter<DestinationEntity>();
        writer.setEntityManagerFactory(destinationEntityManagerFactory.getObject());
        return writer;
    }
}
@SpringBootApplication
@EnableBatchProcessing
public class SpringBatchTwoDatabasesExampleApplication {

    public static void main(String[] args) throws Exception {
        System.exit(SpringApplication.exit(SpringApplication.run(SpringBatchTwoDatabasesExampleApplication.class, args)));
    }
}
有人能帮我吗