当前位置: 首页 > 知识库问答 >
问题:

ClassifierCompositeItemWriter在异常时回滚,但数据部分提交到数据库

欧博简
2023-03-14

我使用ClassifierCompositeItemWriter在一个固定长度的平面文件中插入不同类型的寄存器,并将其写入postgres数据库,其中有多个JDBCBatchItemWriter,每个都位于不同的表中,所有这些都在一个步骤中,然后坚持spring批处理作业,它工作正常,但在激活事务时,它们不会在异常情况下回滚。

例如,我有一个32行的平面文件,1行是页眉记录,然后我将其插入页眉表,然后有30条常规记录和1条页脚记录(按顺序),然后在常规记录的记录29中,它失败,出现数据库转换异常(为测试创建的错误),然后它完成,作业状态为失败,这就可以了,但当我查看数据库时,我发现1条记录为页眉,29条记录为常规数据(除了一条有错误的记录外),没有页脚记录,但我希望事务回滚1条记录为页眉,其余29条记录,但在异常回滚后,它们仍在数据库中。

我不知道我是不是错了,spring批处理中的事务不是这样工作的,或者这是我的配置中的错误还是什么。

以下是ClassifierCompositeItemWriter和一个item writer的代码,其他类似于此:

public ClassifierCompositeItemWriter<DTOBase> altasOffWriterClassifier(DataSource dataSource) {

    BackToBackPatternClassifier classifier = new BackToBackPatternClassifier();
    classifier.setRouterDelegate(dtoWriterClassifier);
    classifier.setMatcherMap(new HashMap<String, JdbcBatchItemWriter<? extends DTOBase>>() {
        private static final long serialVersionUID = -1247536568421993759L;
    {
        put(DTOHeader.class.getTypeName(), headerWriter());
        put(DTOData.class.getTypeName(), dataWriter());
        put(DTOFooter.class.getTypeName(), footerWriterFin());
    }});

    ClassifierCompositeItemWriter<DTOBase> writer = new ClassifierCompositeItemWriter<>();
    writer.setClassifier(classifier);

    return writer;
}

@Bean
public JdbcBatchItemWriter<DTOAltaOFF> altaOffWriter() {
    return new JdbcBatchItemWriterBuilder<DTOData>()
         .dataSource(dataSource)
         .sql("insert into tabla(ticket, identificador, fecha_alta_operacion, "
                + " ordenante, numero, moneda, cif, importe_emisor, "
                + " estado, telefono_destino, fecha_caducidad_hal, concepto, cabecera_num_orden_fichero) "
                + " VALUES (:ticket,:identificador,to_timestamp(:fechaAltaOperacion,'DDMMYYYYHH24MISS'), "
                + " :ordenante,:numero,:moneda,:cif,(cast(:importeEmisor as double precision)/100), "
                + " :estado,:telefonoDestino,to_timestamp(:fechaCaducidadHal,'DDMMYYYYHH24MISS'),:concepto,:idCabecera) ")
         .itemSqlParameterSourceProvider(new BeanPropertyItemSqlParameterSourceProvider<>()) 
         .build();     
}

我的配置类:

@Configuration
@EnableBatchProcessing
@Import({ DataSourceConfig.class })
@PropertySource("classpath:batch.properties")
@ComponentScan({ "..."})
public class BatchConfiguration {

@Autowired
public JobBuilderFactory jobBuilderFactory;

@Autowired
public StepBuilderFactory stepBuilderFactory;

@Autowired
public JobRepository jobRepository;

@Autowired
public DataSource dataSource;

@Bean
public JdbcTemplate getJdbcTemplate() {
    return new JdbcTemplate(dataSource);
}

@Bean
public TaskExecutor taskExecutor() {
    return new SimpleAsyncTaskExecutor();
}

数据源

@Configuration
@EnableTransactionManagement
public class DataSourceConfig {

...some @Value...   
    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {
        DriverManagerDataSource dataSource = new DriverManagerDataSource();
        dataSource.setDriverClassName(driverClassName);
        dataSource.setUrl(datasourceUrl);
        dataSource.setUsername(usuario);
        dataSource.setPassword(clave);
        return dataSource;
    }
}

配置:

@Configuration
@EnableBatchProcessing
@Import({ DataSourceConfig.class })
@PropertySource("classpath:batch.properties")
@ComponentScan({ "..."})
public class BatchConfiguration {

    @Autowired
    public JobBuilderFactory jobBuilderFactory;

    @Autowired
    public StepBuilderFactory stepBuilderFactory;

    @Autowired
    public JobRepository jobRepository;

    @Autowired
    public DataSource dataSource;

    @Bean
    public JdbcTemplate getJdbcTemplate() {
        return new JdbcTemplate(dataSource);
    }

    @Bean
    public TaskExecutor taskExecutor() {
        return new SimpleAsyncTaskExecutor();
    }
}

定义

@Component
@EnableTransactionManagement
public class CustomBatchConfigurer extends DefaultBatchConfigurer {

   private final TaskExecutor taskExecutor;

    public CustomBatchConfigurer(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    @Override
    protected JobLauncher createJobLauncher() throws Exception {
        SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
        jobLauncher.setJobRepository(getJobRepository());
        jobLauncher.setTaskExecutor(this.taskExecutor);
        jobLauncher.afterPropertiesSet();
        return jobLauncher;
    }

    @Autowired
    private DataSource dataSource;

    @Override
    public PlatformTransactionManager getTransactionManager() {
        DataSourceTransactionManager tm = new DataSourceTransactionManager();
        tm.setDataSource(dataSource);
        return tm;
    }
}

任何帮助都会很好。

共有1个答案

李星波
2023-03-14

正如@MahMoudBenHassine在评论中所写,它是块大小,我以这种方式添加了它

@Bean
public Step Step1(@Qualifier("xyzWriterClassifier") ItemWriter<DTOxyz> writer) throws Exception {
    return stepBuilderFactory.get("Step1")
            .<DTOxyz, DTOxyz> chunk(100)
            .reader(dtoXyzItemReader(NULL because WILL_BE_INJECTED))
            .processor(XyzProcessor())
            .writer(writer)
            .build();        
}
 类似资料:
  • 当出现多个矿工挖到同一个区块时,系统会选择累计算力最大的区块。出现这种情况时,有可能需要回滚已经处理过的区块,并处理新区块。 当前处理区块时,都会根据区块哈希,创建一个操作历史记录。当需要回滚区块时,将遍历这个历史记录,用旧的数据覆盖当前数据,并删除该历史记录。从而简单的实现区块的回滚。

  • 所以我有一个网站,我正在建设,它将使用数据库中的数据来填写不同网站上的表格。现在我明白了,这可以很容易地用cURL或python来完成,但是,当我截取和读取post数据时,通常会非常混乱。例如,在此表单中,只有注释和分级选项,但包含所有类型的其他垃圾:

  • 问题内容: 我正在尝试处理以下代码生成的数据: 由于字典很大(10000个键X 10000个列表,每个包含3个元素),很难将其保存在内存中。我一直在寻找一种解决方案,该解决方案将在生成键:值(以列表的形式)对后立即对其进行存储。建议在此处以特定格式(Python)编写和阅读字典,以结合使用ZODB和Btree。 如果这太天真,请忍受我,我的问题是,何时应该调用一次提交数据?如果我在内循环的末尾调用

  • 在本章中,将学习如何通过OrientDB命令行界面回滚未提交的事务。 以下语句是数据库命令的基本语法。 注 - 只有在连接到特定数据库并开始事务后,才能使用此命令。 示例 在这个例子中,我们将使用在前一章中创建的名为的数据库。您将看到回滚事务的操作并使用事务来存储记录。 首先,使用以下命令启动事务。 然后,使用以下命令将值为和的记录插入到表中。 可以使用以下命令从表中检索记录。 如果此命令成功执行

  • 编辑: 首先,我要感谢弗拉德·米哈尔塞亚的帮助。事实上,在Hibernate4中,jboss 9重写事务工厂类和管理器查找类是没有意义的。为了将数据提交到数据库,正如Vlad所说,您只需要: 使用 EJB:有一件事你必须小心,那就是你正确地使用 ejb3 事务。默认的事务绑定上下文是@Nonbinding因此您的事务不会回滚,因为您需要提供您的事务将回滚的异常,这是有道理的。 如果希望回滚所有异常

  • 与RDBMS相似,OrientDB也提供了和等事务概念。 提交是指通过保存对数据库的所有更改来关闭事务。 回滚是指将数据库状态恢复到您打开事务的位置。 以下语句是数据库命令的基本语法。 注 - 只有在连接到特定数据库并开始事务后,才能使用此命令。 示例 在这个例子中,我们将使用在前一章中创建的名为的数据库。将看到提交事务的操作并使用事务来存储记录。 首先,使用以下命令启动事务。 然后,使用以下命令