【问题标题】:Transaction management with Spring Batch使用 Spring Batch 进行事务管理
【发布时间】:2013-07-30 15:44:15
【问题描述】:

我发现实际上是 Spring,我能够设置一些工作。现在,我想使用 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

我发现问题出在交易上。这是entityManager 和transactionManager 的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;
  }

我正在使用JpaItemWriter 将数据存储在数据库中:

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

这是导致异常的代码:javax.persistence.TransactionRequiredException: no transaction is in progress

知道如何解决这个问题吗?

[编辑] 我也把作业定义和步骤定义。我所有的 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;
  }

[编辑]我仍然被这个问题困扰。我遵循了@Sean Patrick Floyd 和@bellabax 的建议,为stepBuilders 设置了一个事务管理器,但我仍然遇到同样的异常。我已经独立于 spring-batch 测试了我的 entityManager,并且我能够将任何数据存储在数据库中。

但是,当使用与 spring 批处理相同的实体管理器时,我有这个异常。

任何人都可以提供更多关于如何在 Spring Batch 中管理事务的见解?谢谢你的帮助?

【问题讨论】:

    标签: java spring jpa spring-batch spring-transactions


    【解决方案1】:

    问题是您正在创建第二个事务管理器 (transactionManager2),但 Spring Batch 正在使用另一个事务管理器来启动事务。如果您使用@EnableBatchProcessing,Spring Batch 会自动注册一个事务管理器以用于其事务,并且您的 JpaTransactionManager 永远不会被使用。 如果要更改 Spring Batch 用于事务的事务管理器,则必须实现接口 BatchConfigurer。看看这个例子:https://github.com/codecentric/spring-batch-javaconfig/blob/master/src/main/java/de/codecentric/batch/configuration/WebsphereInfrastructureConfiguration.java。 在这里,我将事务管理器切换到 WebspherUowTransactionManager,同样您可以将事务管理器切换到其他一些事务管理器。 这是解释它的博客文章的链接:http://blog.codecentric.de/en/2013/06/spring-batch-2-2-javaconfig-part-3-profiles-and-environments/

    【讨论】:

    • 好的,谢谢 Tobias,我没有注意到你教程的那部分。谢谢你的回答。
    • 使用 Spring 4,这个解决方案不能按原样工作,批处理会在主数据源中创建它的模式,这很烦人,并且在你第一次运行后,它每次都会失败,并出现重复的主键错误。此外,还扩展了 BatchConfigurer 的接口。
    • 非常感谢 Tobias Flohre。您的解决方案帮助我解决了我的 spring-batch 问题,即“无法打开 JPA EntityManager 进行事务处理;嵌套异常是 java.lang.IllegalStateException”。它可能与发布的同一问题没有直接关系,但您给出的解决方案有效。我正在使用 2 个数据源(都是 oracle)并遇到了同样的问题。我可以通过使用 @EnableBatchProcessing 注释的类实现 BatchConfigurer 接口并使用我创建的 Injected DataSource 和 PlatformTransactionManager bean 覆盖方法来解决此问题。
    【解决方案2】:

    您需要在步骤定义中明确引用您的事务管理器:

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

    见:5.1.1. Configuring a Step


    啊,看到你使用JavaConfig,你需要将事务管理器分配给TaskletStepBuilder使用builder.transactionManager(transactionManager)(继承自StepBuilderHelper)

    【讨论】:

    • 您好,谢谢您的回答。不幸的是,它仍然不起作用。我仍然有同样的例外。你认为我有正确的事务管理器定义吗?
    • 我还有一个问题,你认为 Spring Batch 中使用的 Transaction 将/必须与 Jpa 中的 Transaction 相同吗?正如您在我的代码中看到的,作者正在使用 JpaWriter,我在其中传递了一个 entityManagerFactory。我认为这就是问题所在。我正在存储数据,但没有绑定到此 jpa 实例的事务。你怎么看?
    • 我花了太长时间才找到这个!谢谢!
    猜你喜欢
    • 2014-12-01
    • 2021-02-07
    • 1970-01-01
    • 2011-08-04
    • 2021-02-20
    • 2015-08-03
    • 2018-08-21
    • 2015-05-31
    • 1970-01-01
    相关资源
    最近更新 更多