【问题标题】:Database session still open after spring batch processing春季批处理后数据库会话仍然打开
【发布时间】:2019-05-09 03:17:20
【问题描述】:

我目前正在开发一个应用程序,该应用程序处理一个大文件文件并将其存储在一个带有 Spring Batch 的 JPA 数据库中。这应要求发生。批处理完成后,您可以使用相同的服务来获取有关根据请求加载到数据库中的数据的信息。

这些请求单独工作,但如果我尝试将它们组合起来,当通过 TestEntityManger 持久化和刷新数据库中的实体时,我的单元测试会出错。

错误是:

javax.persistence.TransactionRequiredException: no transaction is in progress

批处理完成后数据库会话似乎没有正确关闭。但这应该由春季批次处理,但事实并非如此。我的配置有问题还是需要手动关闭会话?如果是这样,我该怎么做?

我的批处理配置如下:

@Configuration
@EnableBatchProcessing
public class BatchConfiguration {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    public CustomerRepository customerRepository;

    @Bean
    public JsonItemReader<Klant> jsonItemReader() {
        return new JsonItemReaderBuilder<Klant>()
                .jsonObjectReader(new JacksonJsonObjectReader<>    (Klant.class))
                .resource(new ClassPathResource("sample-data.json"))
                .name("tradeJsonItemReader")
                .build();
    }

    @Bean
    public KlantItemProcessor processor() {
        return new KlantItemProcessor();
    }

   @Bean
    public RepositoryItemWriter<Customer> writer(){
        return new RepositoryItemWriterBuilder<Customer>()
                .methodName("save")
                .repository(customerRepository)
                .build();
    }

    @Bean
    public Job importUserJob(JobCompletionNotificationListener listener, Step step1) {
        return jobBuilderFactory.get("importUserJob")
                .incrementer(new RunIdIncrementer())
                .listener(listener)
                .flow(step1)
                .end()
                .build();
    }

    @Bean
    public Step step1(RepositoryItemWriter<Customer> writer) {
        return stepBuilderFactory.get("step1")
                .<Klant, Customer> chunk(1)
                .reader(jsonItemReader())
                .processor(processor())
                .writer(writer)
                .build();
    }

}

有人可以向我解释我可以做些什么来解决它吗?

存储库代码:

public interface CustomerRepository extends 
PagingAndSortingRepository<Customer, String> {

    Optional<Customer> findCustomerByCustomerProspectNumber(int customerProspectNumber);

}

单元测试:

@RunWith(SpringRunner.class)
@ActiveProfiles("test")
@DataJpaTest
@Import({SecurityAutoConfiguration.class})
public abstract class BaseAccountRepositoryTest {

    private static final String[] DATA = {
            "/backend/model/exampleCustomer.json"
    };

    @Autowired
    protected TestEntityManager em;

    @Autowired
    protected CustomerRepository customerRepository;

    @Autowired
    protected TransactionRepository transactionRepository;

    @Autowired
    protected AccountRepository accountRepository;


    @Before
    public void init(){
        List<Customer> customersList = GsonUtil.fromJson(Customer.class, DATA);
        customersList.forEach(customer -> {

            em.persistAndFlush(customer);

            customer.getAccounts().forEach(account -> {
                account.setCustomer(customer);
                em.persistAndFlush(account);

                account.getTransactions().forEach(transaction -> {
                    transaction.setAccount(account);
                    em.persistAndFlush(transaction);
                });
            });
        });

        assertEquals(DATA.length, customerRepository.count());
        assertEquals(1, transactionRepository.count());
        assertEquals(1, accountRepository.count());


    }
}

【问题讨论】:

  • 嗨 Ylona 你能在 github 上分享你的代码吗?我解决了类似的问题,但在很久以前,我需要一些上下文
  • 你也在你的存储库上使用@Transactional 吗?
  • 我添加了更多代码。目前我无法分享完整的代码,因为我们使用了很多内部公司包。我将尝试在我可以分享的项目中重现该问题。我没有在单元测试的存储库中使用事务。仅在直接使用存储库的代码类中。我已经尝试将它放在存储库类中,但这并没有改变任何东西。

标签: spring spring-data-jpa spring-batch


【解决方案1】:

由于您使用的是 JPA,因此您需要使用 JpaTransactionManager,因为默认情况下,Spring Batch 将使用 DataSourceTransactionManager(更多详细信息请参见 @EnableBatchProcessingjavadoc),它对您的 JPA 配置一无所知。

您可以使您的BatchConfiguration 扩展DefaultBatchConfigurer 或在您的上下文中添加BatchConfigurer 类型的bean,并通过覆盖getTransactionManager 方法来指定要使用的JpaTransactionManager

这是一个例子(来自documentation):

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

【讨论】:

  • 是的,那是我错过的部分。谢谢!
猜你喜欢
  • 2022-08-02
  • 2014-12-15
  • 2018-05-27
  • 2015-05-13
  • 2017-06-25
  • 2017-10-06
  • 2021-06-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多