我有一个Spring批处理项目,该项目连接到Oracle SQL数据库,并允许使用xls文件导出/导入一些数据。
在我的工作中,我首先在表中进行删除,然后再导入数据。 有时,作业失败是因为要导入的xls中存在问题。 例如:如果我有重复的行,则当作业将行插入数据库时,我将有一个SQLException重复。
我只想不提交任何内容(尤其是删除部分)。 如果工作成功->提交 如果作业失败->回滚
所以我发现我必须将“ setAutocommit”设置为false。
我在工作开始时就加载了数据源,所以我做了一个:
dataSource.getConnection().setAutoCommit(false);
说明有效,但是当我启动工作时,出现此错误:
ERROR o.s.batch.core.step.AbstractStep -
Encountered an error executing step step_excel_sheet_1551274910254 in job importExcelJob
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'scopedTarget.xlsListener'
defined in class path resource [com/adeo/config/ImportExcelConfig.class]:
Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException:
Failed to instantiate [org.springframework.batch.core.StepExecutionListener]:
Factory method 'xlsListener' threw exception; nested exception is
java.lang.NoClassDefFoundError: oracle/xdb/XMLType
at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
~[spring-beans-4.2.4.RELEASE.jar:4.2.4.RELEASE]
作业配置为:
@Configuration
public class ImportExcelConfig {
private static final Logger LOG = LoggerFactory.getLogger("ImportExcelConfig");
@Autowired
private JobBuilderFactory jobBuilderFactory;
@Resource(name = "dataSource")
private DataSource dataSource;
@Autowired
private StepBuilderFactory stepBuilderFactory;
@Bean(name = "importExcelJob")
public Job importExcel(@Qualifier("xlsPartitionerStep") Step xlsPartitionerStep) throws Exception {
return jobBuilderFactory.get("importExcelJob").start(xlsPartitionerStep).build();
}
@Bean(name = "xlsPartitionerStep")
public Step xlsPartitionerStep(@Qualifier("xlsParserSlaveStep") Step xlsParserSlaveStep, XlsPartitioner xlsPartitioner){
return stepBuilderFactory.get("xls_partitioner_step_builder")
.partitioner(xlsParserSlaveStep)
.partitioner("xls_partitioner_step_builder",XlsPartitioner)
.gridSize(3)
.build();
}
@Bean(name = "xlsParserSlaveStep")
@StepScope
public Step xlsParserSlaveStep(@Qualifier("step") Step step,XlsSheetPartitioner xlsPartitioner) throws Exception {
return stepBuilderFactory.get("sheet_partitioner_"+System.currentTimeMillis())
.partitioner(step)
.partitioner("sheet_partitioner_"+System.currentTimeMillis(),XlsPartitioner)
.gridSize(3)
.build();
}
@Bean(name = "step")
@StepScope
public Step step(@Qualifier("xlsReader") PoiItemReader xlsReader,
@Qualifier("jdbcWriter") ItemWriter jdbcWriter,
@Qualifier("xlsListener") StepExecutionListener xlsListener
) throws Exception {
return ((SimpleStepBuilder)stepBuilderFactory
.get("step_excel_sheet_"+System.currentTimeMillis())
.<Object, Map>chunk(1000)
.reader(xlsReader)
.writer(jdbcWriter)
.listener(xlsListener)
).build();
}
@Bean(name = "xlsListener")
@StepScope
@DependsOn
public StepExecutionListener xlsListener() {
XlsStepExecutionListener listener = new xlsStepExecutionListener();
listener.setDataSource(dataSource);
listener.afterPropertiesSet();
return listener;
}
@Bean(name = "jdbcWriter")
@StepScope
@DependsOn
public ItemWriter<Map> jdbcWriter(@Value("#{stepExecutionContext[sheetConfig]}") SheetConfig sheetConfig) throws IOException, ClassNotFoundException {
JdbcBatchItemWriter<Map> writer = new JdbcBatchItemWriter<>();
writer.setItemPreparedStatementSetter(preparedStatementSetter());
String sql = sheetConfig.getSqlInsert().replaceAll("#TABLE#", sheetConfig.getTable());
LOG.info(sql);
writer.setSql(sql);
writer.setDataSource(dataSource);
writer.afterPropertiesSet();
return writer;
}
@Bean
@StepScope
public ItemPreparedStatementSetter preparedStatementSetter(){
return new ItemPreparedStatementSetter();
}
@Bean
public ItemProcessor testProcessor() {
return new TestProcessor();
}
@Bean(name = "xlsReader")
@StepScope
@DependsOn
public PoiItemReader xlsReader(@Value("#{stepExecutionContext[sheetConfig]}") SheetConfig sheetConfig,
@Value("#{stepExecutionContext[xls]}") File xlsFile) throws IOException {
PoiItemReader reader = new PoiItemReader();
reader.setResource(new InputStreamResource(new PushbackInputStream(new FileInputStream(xlsFile))));
reader.setRowMapper(mapRowMapper());
reader.setSheet(sheetConfig.getSheetIndex());
reader.setLinesToSkip(sheetConfig.getLinesToSkip());
return reader;
}
@Bean
@StepScope
@DependsOn
public RowMapper mapRowMapper() throws IOException {
return new MapRowMapper();
}
}
听众是:
public class XlsStepExecutionListener implements StepExecutionListener, InitializingBean {
private final static Logger LOGGER = LoggerFactory.getLogger(XlsStepExecutionListener.class);
@Value("#{stepExecutionContext[sheetConfig]}")
private SheetConfig config;
@Value("#{jobParameters['isFull']}")
private boolean isFull;
@Value("#{stepExecutionContext[supp]}")
private String supp;
private DataSource dataSource;
@Override
public void afterPropertiesSet() {
Assert.notNull(dataSource, "dataSource must be provided");
}
@Override
public void beforeStep(StepExecution stepExecution) {
LOGGER.info("Start - Import sheet {}", config.sheetName);
dataSource.getConnection().setAutoCommit(false);
JdbcTemplate jt = new JdbcTemplate(dataSource);
if(config.sqlDelete != null){
//DELETE DATA
LOGGER.info("beforeStep - PURGE DATA"+config.getSqlDelete().replaceAll("#TABLE#", config.getTable()));
jt.update(config.getSqlDelete().replaceAll("#TABLE#", config.getTable()),supp);
}
}
@Override
public ExitStatus afterStep(StepExecution stepExecution) {
LOGGER.info ("End - Import sheet {}",config.sheetName);
//TODO :
//If status failed -> rollback, if status success : commit
return ExitStatus.COMPLETED;
}
public DataSource getDataSource() {
return dataSource;
}
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
}
在pom.xml中,我有Oracle jar:
<dependency>
<groupId>com.oracle</groupId>
<artifactId>ojdbc6</artifactId>
<version>11.2.0.3</version>
</dependency>
我看到XMLType类在Oracle的另一个jar中,但是我不知道为什么当我简单地修改自动提交模式时需要添加此jar? 另外,我看到,对于我可以从getConnection()。XXXX调用的所有方法,都会发生相同的异常。因此,它不特定于自动提交。
谢谢