2016-07-09 12 views
1

Ich habe ein Problem mit einer Feder-Batch ItemWriter, die auf einem JPA-Repository beruht, um Daten zu aktualisieren.Persist Problem mit einem Frühling Batch ItemWriter mit einem JPA-Repository

Hier ist sie:

@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!! 
      } 
     } 
    } 
} 

Hier ist meine Step Konfiguration:

@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; 
    } 

} 

Der Vollständigkeit halber, hier ist meine Feder Boot-Konfiguration:

@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))); 
    } 
} 

und meine Datenquelle Config :

Ich bemerkte, dass der Ausführungsfluss in die Schreibmethode von ItemWriter gelangte und die messageRepository.save(message); ausgeführt wird, aber die Daten werden nicht aktualisiert.

Ich vermute, es ist eine Transaktion Problem, aber ich bin nicht sicher, wie dieses Problem zu lösen ...

bearbeiten: Ich habe vergessen zu erwähnen, dass ich zwei Postgres-Datenbanken haben:

  1. eins für die Job-Repository-Daten
  2. ein anderes für die Anwendungsdaten.

Ich kann bestätigen, dass Daten in die Job-Repository-Datenbank geschrieben werden. Das Problem ist mit den Anwendungsdaten. Muss ich verteilte Transaktionen verwenden, wenn ich bedenke, dass ich zwei PG-Datenbanken habe?

+0

Es scheint, die einzige Lösung ist die Verwendung eines verteilten TX-Managers. Ich habe eine andere Frage hier geöffnet: http://stackoverflow.com/questions/38323207 – balteo

+0

hi @ balteo, Haben Sie die Lösung? Ich stehe genau vor dem Problem. Wäre toll, wenn Sie die Lösung teilen können. –

+0

Hallo @balteo, hast du eine Lösung für dieses Problem gefunden?Ich versuche, Repository in Writer in einer ähnlichen Weise zu verwenden, wie Sie, mit ähnlich unbefriedigenden Ergebnissen ... :-( –

Antwort

1

Sie sollten @EnableTransactionManagement in Ihrer Hauptklasse. Ich glaube, Spring Boot wird den Transaktionsmanager für Sie erstellen, aber wenn Sie die Standardeinstellungen überschreiben möchten, können Sie want to configure it explicitly.

Spring Batch als bietet APIs for changing transaction attributes.

+0

Vielen Dank für Ihre Antwort. Ich habe '@ EnableTransactionManagement' vergeblich versucht. Ich glaubte, es war für Verwenden Sie mit '@ Transaction', welche Verwendung mit Spring Batch nicht empfohlen wird. – balteo

0

Ich öffnete ein Problem für diese hier:

https://jira.spring.io/browse/BATCH-2642

Grundsätzlich was uns geholfen, wie so primäre Transaktionsmanager konfigurieren sollte:

@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; 
    } 

} 

Und dann autowired Instanz Transaktion mit Manager bei der Konfiguration des Schritts, wie folgt:

@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(); 
    } 
} 

Daten sind jetzt korrekt gespeichert, aber es gibt immer noch etwas Magie, das ich nicht vollständig bekomme ...