Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Closed
spring-issuemaster opened this issue Oct 1, 2017 · 4 comments

Comments

@spring-issuemaster
Copy link
Collaborator

@spring-issuemaster spring-issuemaster commented Oct 1, 2017

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

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Oct 3, 2017

Michael Minella commented

Your "fix" isn't actually correct. We'd expect you to implement a BatchConfigurer that returns the JpaTransactionManager. We're in the process of updating the documentation so that it's more clear how this should behave.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Oct 3, 2017

Petr Dvorak commented

Thank you for the pointer to BatchConfigurer. I was hoping I can save some time by using DefaultBatchConfigurer but of course I can just use if for inspiration and provide implementation that returns the JpaTransactionManager myself. The documentation would be nice, though...

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Aug 30, 2018

Mahmoud Ben Hassine commented

The issue here is the same as BATCH-2294 and BATCH-2724 : Not being able to provide a JpaTransactionManager results in unexpected results (like not saving objects here or incorrect behaviour in BATCH-2724).

This issue would be fixed once we are able to provide a JpaTransactionManager by subclassing DefaulBatchConfigurer and override getTransactionManager. There is an open PR to update the documentation: https://github.com/spring-projects/spring-batch/pull/620/files which would resolve this JIRA Ticket (of type "Documenation"). But the example would work only once BATCH-2294 is resolved.

I'm linking this to BATCH-2294 and adding it to v4.1.0.M3.

@spring-issuemaster

This comment has been minimized.

Copy link
Collaborator Author

@spring-issuemaster spring-issuemaster commented Aug 31, 2018

Mahmoud Ben Hassine commented

The documentation has been updated with an example of how to provide a custom BatchConfigurer (See https://github.com/spring-projects/spring-batch/pull/620/files).

In the case of this issue, it would be something like:

@Bean
 public BatchConfigurer batchConfigurer() {
 	return new DefaultBatchConfigurer() {
 		@Override
 		public PlatformTransactionManager getTransactionManager() {
 			return jpaTransactionManager();
 		}
 	};
 }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
1 participant
You can’t perform that action at this time.