【问题标题】:How to set up two transaction managers?如何设置两个事务管理器?
【发布时间】:2019-02-09 03:30:09
【问题描述】:

我正在开发一个已经设置了事务管理器的 Spring 应用程序。

在一个配置类中,它已经设置了一个从 persistence.xml 读取的实体管理器,然后设置了一个 JpaTransactionManager。

我需要创建一个 Spring Batch 实现,问题是,正如我从不同的帖子中发现的那样,当使用 @EnableBatchProcessing 注释时,似乎注册了第二个事务管理器,我无法在我的内部保存数据小任务。

是否可以使用两个事务管理器或以能够持久保存数据的方式配置我的应用程序?

能否提供示例代码?

提前致谢。

编辑:

这是应用程序配置类,它已经存在于应用程序中:

@Configuration
@ComponentScan({
    ...
})
@EnableJpaRepositories("...")
@EnableTransactionManagement
@EnableJpaAuditing
@Import({SecurityConfig.class})
@PropertySource("classpath:application.properties")
public class ApplicationConfig {

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setPersistenceXmlLocation("classpath:/META-INF/persistence.xml");
        return factory;
    }

    @Bean
    public PlatformTransactionManager transactionManager() {
        JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
        return transactionManager;
    }

    @Bean
    public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
        return new PropertySourcesPlaceholderConfigurer();
    }
}

这是我的批处理配置:

@Configuration
@EnableBatchProcessing
public class BatchConfig {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Autowired
    @Qualifier("entityManagerFactory")
    private LocalEntityManagerFactoryBean batchEntityManagerFactory;


}

我从中得到:

Caused by: org.springframework.beans.factory.BeanCreationException: Could not autowire field: private org.springframework.orm.jpa.LocalEntityManagerFactoryBean com.xxx.xxx.xxx.configuration.BatchConfig.batchEntityManagerFactory; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [org.springframework.orm.jpa.LocalEntityManagerFactoryBean] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true), @org.sp
ringframework.beans.factory.annotation.Qualifier(value=entityManagerFactory)}

编辑 2: 这就是我所做的:

@EnableJpaRepositories("xxx")
@Configuration
@EnableBatchProcessing
@PropertySource("classpath:application.properties")
public class BatchConfig {

    @Autowired
    private JobBuilderFactory jobs;

    @Autowired
    private StepBuilderFactory steps;

    @Autowired
    private ReportReaderProcessor reportReaderProcessor;

    @Bean
    public LocalContainerEntityManagerFactoryBean entityManagerFactory() {

        LocalContainerEntityManagerFactoryBean factory = new LocalContainerEntityManagerFactoryBean();
        factory.setPersistenceXmlLocation("classpath:/META-INF/persistence.xml");
        return factory;
    }

    @Bean
    public BatchConfigurer batchConfigurer() {
        return new DefaultBatchConfigurer() {
            @Override
            public PlatformTransactionManager getTransactionManager() {
                JpaTransactionManager jpaTransactionManager = new JpaTransactionManager();
                jpaTransactionManager.setEntityManagerFactory(entityManagerFactory().getObject());
                return jpaTransactionManager;
            }
        };
    }
    @Bean
    public JobRepository jobRepository() throws Exception {
        MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
        factory.setTransactionManager(batchConfigurer().getTransactionManager());
        return (JobRepository) factory.getObject();
    }

    @Bean
    public SimpleJobLauncher simpleJobLauncher() throws Exception {
        SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
        simpleJobLauncher.setJobRepository(jobRepository());
        return simpleJobLauncher;
    }

    @Bean
    public Step readReports() {
        return steps
                .get("readReports")
                .tasklet(reportReaderProcessor)
                .build();
    }

    @Bean
    public Job reportJob() {
        return jobs
                .get("submitReportJob")
                .start(readReports())
                .build();
    }
}

但现在我收到另一个错误:

15:47:23,657 ERROR [stderr] (pool-36-thread-1) org.springframework.transaction.InvalidIsolationLevelException: DefaultJpaDialect does not support custom isolation levels due to limitations in standard JPA. Specific arrangements may be implemented in custom JpaDialect variants.

【问题讨论】:

    标签: spring jpa spring-batch


    【解决方案1】:

    此案例存在一个未解决的问题:https://jira.spring.io/browse/BATCH-2294,已在版本 4.1.0.M3 中修复。要使用自定义事务管理器,您需要在应用程序上下文中提供BatchConfigurer,例如:

    @Bean
    public BatchConfigurer batchConfigurer() {
        return new DefaultBatchConfigurer() {
            @Override
            public PlatformTransactionManager getTransactionManager() {
               return new MyTransactionManager();
            }
        };
    }
    

    【讨论】:

    • 您仍然需要提供 BatchConfigurer 并实现 getTransactionManager 返回现有的事务管理器。 Spring Batch 不会决定使用哪个事务管理器。如果您尝试使用 4.1.0.M3 版本并给我们您的反馈,那就太好了!非常感谢。
    • 这仍然是让 Spring Batch 在 4.1.2 中使用 JpaTransactionManager 的方法吗?在尝试使用我的 jpa 存储库时,我发现自己出现错误“键 [HikariDataSource (HikariPool-1)] 的值 [org.springframework.jdbc.datasource.ConnectionHolder@32c3d9cf]”,但随后我在下面找到了您的答案在这篇文章中线程gitter.im/spring-batch/Lobby?at=5dc40c9b9c39821509fbf48e.and。我已经成功地让事情与这个解决方案一起工作,但想确保它在当前版本的 Spring Batch 中是正确的方法。
    • 是的,自 4.1.0.M3 以来这没有改变。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-05-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-07
    • 1970-01-01
    相关资源
    最近更新 更多