Uploaded image for project: 'Spring Batch'
  1. Spring Batch
  2. BATCH-2642

Document how to make Spring Batch work with Spring Data JPA repositories

    Details

    • Type: Improvement
    • Status: Resolved
    • Priority: Minor
    • Resolution: Complete
    • Affects Version/s: 3.0.9, 4.0.1
    • Fix Version/s: 4.1.0, 4.1.0.M3
    • Component/s: Documentation
    • Labels:
      None

      Description

      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).

        Attachments

          Issue Links

            Activity

              People

              • Assignee:
                mminella Michael Minella
                Reporter:
                joshis Petr Dvorak
              • Votes:
                0 Vote for this issue
                Watchers:
                3 Start watching this issue

                Dates

                • Created:
                  Updated:
                  Resolved: