I have an issue with a spring batch ItemWriter
that relies on a JPA repository in order to update data.
Here it is:
@Component
public class MessagesDigestMailerItemWriter implements ItemWriter<UserAccount> {
private static final Logger log = LoggerFactory.getLogger(MessagesDigestMailerItemWriter.class);
@Autowired
private MessageRepository messageRepository;
@Autowired
private MailerService mailerService;
@Override
public void write(List<? extends UserAccount> userAccounts) throws Exception {
log.info("Mailing messages digests and updating messages notification statuses");
for (UserAccount userAccount : userAccounts) {
if (userAccount.isEmailNotification()) {
mailerService.mailMessagesDigest(userAccount);
}
for (Message message : userAccount.getReceivedMessages()) {
message.setNotificationSent(true);
messageRepository.save(message);//NOT SAVING!!
}
}
}
}
Here is my Step
configuration:
@Configuration
public class MailStepConfiguration {
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Autowired
private EntityManagerFactory entityManagerFactory;
@Autowired
private MessagesDigestMailerItemWriter itemWriter;
@Bean
public Step messagesDigestMailingStep() {
return stepBuilderFactory.get("messagesDigestMailingStep")//
.<UserAccount, UserAccount> chunk(1)//
.reader(jpaPagingItemReader(entityManagerFactory))//
.writer(itemWriter)//
.build();
}
@Bean(destroyMethod = "")
@StepScope
public static ItemReader<UserAccount> jpaPagingItemReader(EntityManagerFactory entityManagerFactory) {
final JpaPagingItemReader<UserAccount> reader = new JpaPagingItemReader<>();
reader.setEntityManagerFactory(entityManagerFactory);
reader.setQueryString("SELECT ua FROM UserAccount ua JOIN FETCH ua.receivedMessages msg WHERE msg.notificationSent = false AND msg.messageRead = false");
return reader;
}
}
For completeness sake, here is my spring boot configuration:
@Configuration
@EnableBatchProcessing
@EnableAutoConfiguration
@ComponentScan("com.bignibou.batch.configuration")
public class Batch {
public static void main(String[] args) {
System.exit(SpringApplication.exit(new SpringApplicationBuilder(Batch.class).web(false).run(args)));
}
}
and my datasource config:
@Configuration
@EnableJpaRepositories({ "com.bignibou.repository" })
@EntityScan("com.bignibou.domain")
public class DatasourceConfiguration {
@Bean
@ConfigurationProperties("spring.datasource.batch")
public DataSource batchDatasource() {
return DataSourceBuilder.create().build();
}
@Bean
@Primary
@ConfigurationProperties("spring.datasource.application")
public DataSource applicationDatasource() {
return DataSourceBuilder.create().build();
}
}
I noticed that the execution flow get into the ItemWriter's write method and the messageRepository.save(message);
does get executed but the data is not updated.
I suspect it is a transaction issue but I am not sure how to solve this problem...
edit: I forgot to mention that I have two Postgres databases:
- one for the job repository data
- another one for the application data.
I can confirm that data is written into the job repository database. The issue is with the application data. I am required to use distributed transactions bearing in mind the fact that I have two PG databases?