简体   繁体   English

使用Spring Batch进行事务管理

[英]Transaction management with Spring Batch

I am discovering actually Spring and I am able to setup some jobs. 我发现实际上是Spring,我可以设置一些工作。 Now, I would like to save my imported datas in a database using Hibernate/JPA and I keep getting this error : 现在,我想使用Hibernate / JPA将我导入的数据保存在数据库中,并且我不断收到此错误:

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

I see that the problem is with the transaction. 我看到问题出在交易上。 Here is my spring java config for the entityManager and the transactionManager : 这是我对entityManagertransactionManager spring java配置:

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

I am using the JpaItemWriter to store the datas in the database : 我使用JpaItemWriter将数据存储在数据库中:

 @Bean
  public ItemWriter<EntiteJuridiqueJPA> writer()
  {
    JpaItemWriter<EntiteJuridiqueJPA> writer = new JpaItemWriter<EntiteJuridiqueJPA>();    
    writer.setEntityManagerFactory(entityManagerFactory.getObject());
    return writer;
  }

This is the code that causes the exception : javax.persistence.TransactionRequiredException: no transaction is in progress 这是导致异常的代码: javax.persistence.TransactionRequiredException: no transaction is in progress

Any idea to how to solve this problem? 有什么想法如何解决这个问题?

[Edit] I am putting also the Job definition and the step definition. [编辑]我还提出了Job定义和步骤定义。 All my Spring configuration is written in Java. 我的所有Spring配置都是用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;
  }

[EDIT] I am still stuck with this problem. [编辑]我仍然坚持这个问题。 I have followed the suggestions of @Sean Patrick Floyd and @bellabax by setting a transaction manager for the stepBuilders, but I still get the same exception. 我通过为stepBuilders设置事务管理器来遵循@Sean Patrick Floyd和@bellabax的建议,但我仍然得到相同的异常。 I have tested my entityManager independtly of spring-batch and I am able to store any data in the database. 我已经测试了我的entityManager独立于spring-batch,我能够在数据库中存储任何数据。

But, when using the same entity manager with spring batch, I have this exception. 但是,当使用弹簧批的相同实体管理器时,我有这个例外。

Anyone can give more insights how transactions are managed within spring batch? 任何人都可以提供更多见解如何在春季批次内管理交易? Thx for your help? 谢谢你的帮助?

The problem is that you are creating a second transaction manager (transactionManager2), but Spring Batch is using another transaction manager for starting transactions. 问题是您正在创建第二个事务管理器(transactionManager2),但Spring Batch正在使用另一个事务管理器来启动事务。 If you use @EnableBatchProcessing, Spring Batch automatically registers a transaction manager to use for its transactions, and your JpaTransactionManager never gets used. 如果使用@EnableBatchProcessing,Spring Batch会自动注册一个事务管理器用于其事务,并且您的JpaTransactionManager永远不会被使用。 If you want to change the transaction manager that Spring Batch uses for transactions, you have to implement the interface BatchConfigurer. 如果要更改Spring Batch用于事务的事务管理器,则必须实现BatchConfigurer接口。 Take a look at this example: https://github.com/codecentric/spring-batch-javaconfig/blob/master/src/main/java/de/codecentric/batch/configuration/WebsphereInfrastructureConfiguration.java . 看一下这个例子: https//github.com/codecentric/spring-batch-javaconfig/blob/master/src/main/java/de/codecentric/batch/configuration/WebsphereInfrastructureConfiguration.java Here I am switching the transaction manager to a WebspherUowTransactionManager, and in the same way you can switch the transaction manager to some other transaction manager. 在这里,我将事务管理器切换到WebspherUowTransactionManager,并以同样的方式将事务管理器切换到其他事务管理器。 Here's the link to the blog post explaining it: http://blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/ 以下是解释它的博客文章的链接: http//blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/

You need to explicitly reference your Transaction Manager in your step definition: 您需要在步骤定义中明确引用您的事务管理器:

<job id="sampleJob" job-repository="jobRepository">
    <step id="step1">
        <tasklet transaction-manager="transactionManager">
            <chunk reader="itemReader" writer="itemWriter" commit-interval="10"/>
        </tasklet>
    </step>
</job>

See: 5.1.1. 见: 5.1.1。 Configuring a Step 配置步骤


Ah, seeing that you use JavaConfig, you need to assign the transaction manager to the TaskletStepBuilder using builder.transactionManager(transactionManager) (inherited from StepBuilderHelper ) 啊,看到你使用JavaConfig,你需要使用builder.transactionManager(transactionManager)将事务管理器分配给TaskletStepBuilder (继承自StepBuilderHelper

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM