首页 > 解决方案 > 无法使用 Spring Batch + Spring 数据在数据库中插入行

问题描述

我正在使用其中 db 表没有键的旧数据库。对于 java Sake,我必须使用 Id 注释。我的目标是从 .dat 文件中读取数据并将其插入表中。我正在为上述目的使用弹簧批次。为了提高性能,使用了线程。但是我遇到了我无法弄清楚的插入/更新问题。我参考了许多来源,但似乎没有一个能解决我的目的。请通过提供一些适当的解决方案或参考来帮助我。提前致谢...

实体.java

@Entity
@Table(name = "int_repl_mkt_val")
public class IntReplMktVal implements Serializable {

    private static final long serialVersionUID = 1L;

    @EmbeddedId
    private IntReplMktValId id;

    @Column(name = "acct_sys_cd")
    private String acctSysCd;

    @Column(name = "co_num", nullable = false)
    private Integer coNum;

    @Column(name = "last_mod_tmstmp")
    @Temporal(TemporalType.TIMESTAMP)
    private Date lastModTmstmp;

    @Column(name = "pim_owned", nullable = false)
    private String pimOwned;

    @Column(name = "position", nullable = false)
    private BigDecimal position;

    @Column(name = "pricing_plan")
    private String pricingPlan;

    @Column(name="source_system",nullable=false)
    private String sourceSystem;

    ... getter and setter

}

嵌入式类.java

@Embeddable
public class IntReplMktValId implements Serializable 
{

    private static final long serialVersionUID = 4824041485763129937L;

    @Column(name = "acct_id",nullable=false)
    private Integer acctId;

    @Column(name = "asset_id",nullable=false)
    private Integer assetId;

    ... getter and setter
}

jpaRepository.class

@Repository
public interface IntReplMktValRepository extends JpaRepository<IntReplMktVal, IntReplMktValId> 
{

}

BatchConfiguration.class

@Configuration
public class IMAPPositionBatchConfiguration 
{
    @Autowired
    JobBuilderFactory jobBuilderFactory;

    @Autowired
    StepBuilderFactory stepBuilderFactory;

    @StepScope
    @Bean(name="imapPositionReader")
    public FlatFileItemReader<IMAPPositionInputMapperDTO> reader(@Value("#{jobParameters['fileName']}") String fileName) throws IOException 
    {
        FlatFileItemReader<IMAPPositionInputMapperDTO> newBean = new FlatFileItemReader<>();
        newBean.setName("fileReader");
        newBean.setResource(new InputStreamResource(FileUtils.openInputStream(new File(fileName))));
        newBean.setLineMapper(this.lineMapper());
        newBean.setLinesToSkip(1);
        return newBean;
    }

    public DefaultLineMapper<IMAPPositionInputMapperDTO> lineMapper() 
    {
        DefaultLineMapper<IMAPPositionInputMapperDTO> lineMapper = new DefaultLineMapper<>();
        lineMapper.setLineTokenizer(this.lineTokenizer());
        IMAPPositionReader imapPositionReader = new IMAPPositionReader();
        lineMapper.setFieldSetMapper(imapPositionReader);
        return lineMapper;
    }

    public DelimitedLineTokenizer lineTokenizer() 
    {
        DelimitedLineTokenizer tokenizer = new DelimitedLineTokenizer();
        tokenizer.setDelimiter("|");
        tokenizer.setNames("field1","field2","field3");
        tokenizer.setIncludedFields(5,4,7);
        return tokenizer;
    }

    public ItemProcessor<IMAPPositionInputMapperDTO, IntReplMktVal> processor() 
    {
        return new IMAPPositionProcessor();
    }

    @Bean(name="imapPositionBatchWriter")
    public ItemWriter<IntReplMktVal> writer() 
    {
        return new IMAPPositionWriter();
    }

    @Bean(name="imapPositionListener")
    public JobExecutionListenerSupport jobCompletionListener()
    {
        return new IMAPPositionJobListener();
    }

    @Bean(name="imapPositionTaskExecutor")    
    public ThreadPoolTaskExecutor taskExecutor() 
    {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        executor.setCorePoolSize(50);
        executor.setMaxPoolSize(100);
        return executor;
    }

    @Bean(name="imapPositionStep")
    public Step step(@Autowired @Qualifier("imapPositionTaskExecutor")TaskExecutor taskExecutor) throws IOException 
    {
        return stepBuilderFactory.get("imapPositionStep")
                .<IMAPPositionInputMapperDTO, IntReplMktVal>chunk(100)
                .reader(this.reader(null))
                .processor(this.processor())
                .writer(this.writer())
                .taskExecutor(taskExecutor)
                .build();
    }

    @Bean(name="imapPositionFileImportJob")
    public Job importUserJob(@Autowired @Qualifier("imapPositionStep") Step step) 
    {
        return jobBuilderFactory
                .get("imapPositionFileImportJob"+new Date())
                .incrementer(new RunIdIncrementer())
                .listener(this.jobCompletionListener())
                .flow(step)
                .end()
                .build();
    }

}

BatchWriter.java

public class IMAPPositionWriter implements ItemWriter<IntReplMktVal>
{
    @Autowired
    IntReplMktValRepository intReplMktValRepository;

    @Override
    public void write(List<? extends IntReplMktVal> items) throws Exception 
    {
        intReplMktValRepository.saveAll(items);     
    }

}

错误日志

2019-06-07 17:22:01,522 ERROR [scopedTarget.imapPositionTaskExecutor-4] org.hibernate.internal.ExceptionMapperStandardImpl : HHH000346: Error during managed flush [org.hibernate.HibernateException: Duplicate identifier in table for: [com.capgroup.horizon.pricecapture.entities.IntReplMktVal#component[acctId,assetId]{assetId=274800, acctId=1}]]

注意:无论重复或任何其他问题,我都必须将所有数据插入表中,因为未定义键,因此每个数据都是有效的。

标签: spring-bootspring-data-jpaspring-dataspring-batch

解决方案


实际上问题是由于在持久上下文中发现的重复,通过将块大小设置为 1 来解决。


推荐阅读