La gestion des transactions avec Spring Batch
Je découvre réellement Printemps et je suis en mesure de configurer certaines tâches. Maintenant, je voudrais sauvegarder mes données importées dans une base de données en utilisant Hibernate/JPA, et je reçois cette erreur :
14:46:43.500 [main] ERROR o.s.b.core.step.AbstractStep - Encountered an error executing the step javax.persistence.TransactionRequiredException: no transaction is in progress
Je vois que le problème est avec la transaction. Voici ma source java config pour la entityManager
et la transactionManager
:
@Configuration
public class PersistenceSpringConfig implements EnvironmentAware
{
@Bean
public LocalContainerEntityManagerFactoryBean entityManagerFactory() throws Exception
{
//Initializes the entity manager
LocalContainerEntityManagerFactoryBean factoryBean = new LocalContainerEntityManagerFactoryBean();
factoryBean.setPersistenceUnitName(PERSISTENCE_UNIT_NAME);
factoryBean.setJpaVendorAdapter(new HibernateJpaVendorAdapter());
factoryBean.setDataSource(dataSource());
//Scans the database model
factoryBean.setPackagesToScan(EntiteJuridiqueJPA.class.getPackage().getName());
//Defines the Hibernate properties
Properties jpaProperties = new Properties();
jpaProperties.setProperty("hibernate.show_sql", "false");
jpaProperties.setProperty("hibernate.format_sql", "false");
String connectionURL = "jdbc:h2:file:" + getDatabaseLocation();
jpaProperties.setProperty("hibernate.connection.url", connectionURL);
jpaProperties.setProperty("hibernate.connection.username", "sa");
jpaProperties.setProperty("hibernate.connection.driver_class", "org.h2.Driver");
jpaProperties.setProperty("hibernate.dialect", H2Dialect.class.getName());
jpaProperties.setProperty("hibernate.hbm2ddl.auto", "create");
jpaProperties.setProperty("hibernate.hbm2ddl.import_files_sql_extractor", "org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor");
jpaProperties.setProperty("hibernate.hbm2ddl.import_files",
"org/springframework/batch/core/schema-drop-h2.sql,org/springframework/batch/core/schema-h2.sql");
factoryBean.setJpaProperties(jpaProperties);
return factoryBean;
}
@Bean
public PlatformTransactionManager transactionManager2() throws Exception
{
EntityManagerFactory object = entityManagerFactory().getObject();
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(object);
return jpaTransactionManager;
}
Je suis en utilisant le JpaItemWriter pour stocker les données dans la base de données :
@Bean
public ItemWriter<EntiteJuridiqueJPA> writer()
{
JpaItemWriter<EntiteJuridiqueJPA> writer = new JpaItemWriter<EntiteJuridiqueJPA>();
writer.setEntityManagerFactory(entityManagerFactory.getObject());
return writer;
}
C'est le code qui provoque l'exception : javax.persistence.TransactionRequiredException: no transaction is in progress
Aucune idée de comment résoudre ce problème?
[Edit] je suis en train de monter aussi la définition du Travail et de l'étape de la définition. Tous mes Printemps de configuration est écrit en Java.
@Configuration
@EnableBatchProcessing
@Import(PersistenceSpringConfig.class)
public class BatchSpringConfig
{
@Autowired
private JobBuilderFactory jobBuilders;
@Autowired
private StepBuilderFactory stepBuilders;
@Autowired
private DataSource dataSource;
@Autowired
private LocalContainerEntityManagerFactoryBean entityManagerFactory;
@Bean
public Step step()
{
return stepBuilders.get("step").<EntiteJuridique, EntiteJuridiqueJPA> chunk(5).reader(cvsReader(null))
.processor(processor()).writer(writer()).listener(processListener()).build();
}
@Bean
@StepScope
public FlatFileItemReader<EntiteJuridique> cvsReader(@Value("#{jobParameters[input]}") String input)
{
FlatFileItemReader<EntiteJuridique> flatFileReader = new FlatFileItemReader<EntiteJuridique>();
flatFileReader.setLineMapper(lineMapper());
flatFileReader.setResource(new ClassPathResource(input));
return flatFileReader;
}
@Bean
public LineMapper<EntiteJuridique> lineMapper()
{
DefaultLineMapper<EntiteJuridique> lineMapper = new DefaultLineMapper<EntiteJuridique>();
DelimitedLineTokenizer lineTokenizer = new DelimitedLineTokenizer();
lineTokenizer.setDelimiter(";");
lineTokenizer.setNames(new String[] { "MEGA_ENTITE", "PORTEFEUILLE", "MEGA_ENTITE", "Libellé" });
BeanWrapperFieldSetMapper<EntiteJuridique> fieldSetMapper = new BeanWrapperFieldSetMapper<EntiteJuridique>();
fieldSetMapper.setTargetType(EntiteJuridique.class);
lineMapper.setLineTokenizer(lineTokenizer);
lineMapper.setFieldSetMapper(fieldSetMapper);
return lineMapper;
}
@Bean
public Job dataInitializer()
{
return jobBuilders.get("dataInitializer").listener(protocolListener()).start(step()).build();
}
@Bean
public ItemProcessor<EntiteJuridique, EntiteJuridiqueJPA> processor()
{
return new EntiteJuridiqueProcessor();
}
@Bean
public ItemWriter<EntiteJuridiqueJPA> writer()
{
JpaItemWriter<EntiteJuridiqueJPA> writer = new JpaItemWriter<EntiteJuridiqueJPA>();
writer.setEntityManagerFactory(entityManagerFactory.getObject());
return writer;
//return new EntiteJuridiqueWriter();
}
@Bean
public ProtocolListener protocolListener()
{
return new ProtocolListener();
}
@Bean
public CSVProcessListener processListener()
{
return new CSVProcessListener();
}
@Bean
public PlatformTransactionManager transactionManager2() throws Exception
{
EntityManagerFactory object = entityManagerFactory.getObject();
JpaTransactionManager jpaTransactionManager = new JpaTransactionManager(object);
return jpaTransactionManager;
}
[MODIFIER] je suis toujours bloqué avec ce problème. J'ai suivi les suggestions de @Sean Patrick Floyd et @bellabax par la fixation d'un gestionnaire de transactions pour la stepBuilders, mais j'ai toujours la même exception. J'ai testé mes entityManager independtly de printemps-lot et je suis capable de stocker les données dans la base de données.
Mais, lors de l'utilisation de la même entité gestionnaire avec spring batch, j'ai cette exception.
N'importe qui peut donner plus de points de vue la façon dont les transactions sont gérées au sein de spring batch? Merci pour votre aide?
OriginalL'auteur Dimitri | 2013-07-30
Vous devez vous connecter pour publier un commentaire.
Le problème, c'est que vous êtes la création d'un deuxième gestionnaire de transactions (transactionManager2), mais Spring Batch est d'utiliser un autre gestionnaire de transactions pour le démarrage des opérations. Si vous utilisez @EnableBatchProcessing, Spring Batch enregistre automatiquement un gestionnaire de transactions à utiliser pour ses opérations, et votre JpaTransactionManager n'est jamais utilisée.
Si vous souhaitez modifier le gestionnaire de transactions que Spring Batch utilise pour les transactions, vous devez implémenter l'interface BatchConfigurer. Jetez un oeil à cet exemple: https://github.com/codecentric/spring-batch-javaconfig/blob/master/src/main/java/de/codecentric/batch/configuration/WebsphereInfrastructureConfiguration.java.
Ici, je suis de commutation le gestionnaire de transactions pour un WebspherUowTransactionManager, et de la même manière, vous pouvez basculer le gestionnaire de transactions à un autre gestionnaire de transactions.
Voici le lien vers le blog de l'expliquer: http://blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/
À l'aide de Printemps 4, cette solution ne fonctionne pas comme il est, de lot, de créer du schéma dans la Principale source de données, ce qui est gênant, et après votre premier run, il échouera à chaque fois avec le double de la clé primaire des erreurs. En outre, l'interface de BatchConfigurer a été étendu.
OriginalL'auteur Tobias Flohre
Vous devez explicitement référence à votre Gestionnaire de Transactions dans votre démarche de définition:
Voir: 5.1.1. La configuration d'une Étape
Ah, voyant que vous utilisez JavaConfig, vous devez attribuer le gestionnaire de transactions à l'
TaskletStepBuilder
à l'aide debuilder.transactionManager(transactionManager)
(héritée deStepBuilderHelper
)Et j'ai une autre question, pensez-vous que la Transaction utilisée dans spring batch va/doit être le même que celui de Jpa? Comme vous le voyez dans mon code, l'écrivain est à l'aide de JpaWriter où je passe une entityManagerFactory. Je pense que c'est le problème. Je suis le stockage de données, mais il n'y a pas de transactions liés à cette jpa instance. Qu'en pensez-vous?
M'a pris beaucoup trop de temps à trouver ce! Merci!!!!
OriginalL'auteur Sean Patrick Floyd