我遇到弹簧批ItemWriter
的问题,它依赖于JPA存储库来更新数据。
这是:
@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!!
}
}
}
}
这是我的Step
配置:
@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;
}
}
为了完整起见,这是我的弹簧启动配置:
@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)));
}
}
和我的数据源配置:
@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();
}
}
我注意到执行流程已进入ItemWriter的写入方法,而messageRepository.save(message);
确实已执行,但数据未更新。
我怀疑这是一个交易问题,但我不确定如何解决这个问题...
编辑:我忘了提到我有两个 Postgres数据库:
我可以确认数据已写入作业存储库数据库。问题在于应用程序数据。我需要使用分布式事务,记住我有两个PG数据库?
答案 0 :(得分:1)
您应该在主要课程中@EnableTransactionManagement
。我相信Spring Boot会为你创建事务管理器,但是如果你想覆盖默认值,你可以want to configure it explicitly。
Spring Batch比提供APIs for changing transaction attributes。
答案 1 :(得分:0)
我在这里打开了一个问题:
https://jira.spring.io/browse/BATCH-2642
原则上,帮助我们的是如此配置主要事务管理器:
@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;
}
}
然后在配置步骤时使用事务管理器的自动连接实例,如下所示:
@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();
}
}
现在数据已经被正确保留了,但仍有一些魔力我还没有完全得到......