I'm using a ClassifierCompositeItemWriter to insert different kinds of registers stored inside one fixed length flat file, and writing it into a postgres database with multiple JdbcBatchItemWriters each one in a different table, all this inside a step then insiste a spring batch job, it works fine, but when activating transactions they arent rolling back in case of an exception.
For example I have a 32 lines flat file, 1 line is a header record and then I insert it in header table, then there are 30 regular records and 1 footer record (in order), then in the record 29 of the regular one it fails with an database conversion exception (error created for testing) and then it finished with failed status for the job and thats ok, but when I look at the database I have found the 1 record for header, 29 records for regular data (except one with error) and no footer record, but I hope transaction rollback that 1 record for header and the other 29 records, but they are still in database after exception rollback.
I dont know if I'm wrong and transactions in spring batch don't work that way or if it's a mistake in my configuration or what.
Here is the code for ClassifierCompositeItemWriter and one item writer others are similar to this:
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();
}
my configuration classes:
@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();
}
Datasource
@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:
@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();
}
}
Custom:
@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;
}
}
Any help would be great.