Skip to content

Document how to make Spring Batch work with Spring Data JPA repositories [BATCH-2642] #961

Closed
@spring-projects-issues

Description

@spring-projects-issues

Petr Dvorak opened BATCH-2642 and commented

We are using Spring Boot and we were struggling with a following issue: We needed to use our Spring Data JPA repositories (interfaces extending 'CrudRepository') in a Spring Batch writer and for some reason, the 'save(s)' method did not work for us - method got called, no exception or error was in the log, but the object was not persisted. In principle, it was exactly the same issue as the one reported here:

https://stackoverflow.com/questions/38287298/persist-issue-with-a-spring-batch-itemwriter-using-a-jpa-repository

The offending part was this one:

@Component
public class MessagesDigestMailerItemWriter implements ItemWriter<UserAccount> {

    @Autowired
    private MessageRepository messageRepository;

    @Autowired
    private MailerService mailerService;

    @Override
    public void write(List<? extends UserAccount> userAccounts) throws Exception {

        for (UserAccount userAccount : userAccounts) {
            if (userAccount.isEmailNotification()) {
                mailerService.mailMessagesDigest(userAccount);
            }
            for (Message message : userAccount.getReceivedMessages()) {
                message.setNotificationSent(true);
                messageRepository.save(message); //NOT SAVING!!
            }
        }
    }
}

We finally fixed the issue by adding following code:

@Configuration
public class JpaConfig {

    private final DataSource dataSource;

    @Autowired
    public JpaConfig(@Qualifier("dataSource") DataSource dataSource) {
        this.dataSource = dataSource;
    }

    @Bean
    @Primary
    public JpaTransactionManager jpaTransactionManager() {
        final JpaTransactionManager transactionManager = new JpaTransactionManager();
        transactionManager.setDataSource(dataSource);
        return transactionManager;
    }

}

... and later, using autowired transaction manager for the step config:

@Autowired
private PlatformTransactionManager transactionManager;

private TaskletStep buildTaskletStep() {
        return stepBuilderFactory.get("SendCampaignStep")
                    .<UserAccount, UserAccount>chunk(pushServiceConfiguration.getCampaignBatchSize())
                    .reader(userAccountItemReader)
                    .processor(userAccountItemProcessor)
                    .writer(userAccountItemWriter)
                    .transactionManager(transactionManager)
                    .build();
    }
}

... which replaces the default DataSourceTransactionManager in our extension of DefaultBatchConfigurer - suddenly, the data is written in the repository correctly.

However, the whole fix feels a bit magical and we could use some official documentation on how to use Spring Boot Data JPA repositories inside Spring Batch writer (or other Spring Batch contexts).


Affects: 3.0.9, 4.0.1

Issue Links:

  • BATCH-2294 Overriding transaction management
    ("depends on")

Referenced from: pull request #620

Backported to: 4.1.0.M3

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions