【问题标题】:How can I avoid duplicate values when loading data using a spring batch job?使用弹簧批处理作业加载数据时如何避免重复值?
【发布时间】:2019-04-23 19:26:51
【问题描述】:

我有一个 spring 批处理程序,它从一个数据库读取数据,然后处理数据,然后写入 Oracle 数据库。该批处理程序每​​天按计划运行一次。如何避免每次运行时都添加相同的记录,并且只添加源数据库中的新值?

【问题讨论】:

    标签: spring oracle spring-batch


    【解决方案1】:

    一种选择是创建唯一索引(或主键,如果可能(取决于您是否允许空值)),这将导致 Oracle 自动拒绝其列违反唯一性的所有行。

    其他选项需要一些编程。

    [编辑:“静默”跳过错误]

    这就是我的意思:

    for cur_r in (select col1, col2
                  from another_table@db_link)
    loop
      begin        --> you need inner BEGIN-EXCEPTION-END block
        insert into new_table (col1, col2)
          values (cur_r.col1, cur_r.col2);
      exception
        when dup_val_on_index then
          null;
      end;
    end loop;
    

    另一个选项使用纯 SQL(即没有 PL/SQL 的 循环):

    insert into new_table (col1, col2)
      select col1, col2
      from another_table@db_link
      where (col1, col2) not in (select col1, col2 
                                 from new_table);
    

    此选项甚至不需要唯一索引(但这不会造成损害),因为NOT IN 不会插入其列值已存在于目标表中的行。

    【讨论】:

    • 很遗憾该表没有唯一值
    • 那么,您如何检测重复项?不必在单个列上强制执行唯一性。 ALL COLUMNS 的组合可以是唯一的。例如,基于 Scott 的 DEPT 表:create unique index ui_dept on dept (deptno, dname, loc)
    • 啊,好吧。所以我认为除了审计列之外的每一列都被认为是唯一的。所以我会为这些列创建一个索引?
    • 对,让它独一无二。创建它需要一些时间(如果该表目前不包含太多行),您将能够立即对其进行测试。
    • 好的,如果要添加一个副本,它会被忽略吗?还是抛出错误?
    【解决方案2】:

    您似乎担心不会多次处理相同的源记录。如果是这种情况,您可以在 源表 上添加一个字段,指示数据已被提取。

    哦,而且 - 在您的表上放置一个唯一的主键。他们全部。即使是那些你认为你不需要它的地方。您今天添加的主键是您以后不会说的那个,“该死。我希望那个表有一个主键”。 Don't ask me how I know...

    祝你好运。

    【讨论】:

      【解决方案3】:

      我猜你正在使用 RepositoryItemReader 作为源。如果是这种情况,您可以使用 @Query 在源存储库中添加自定义方法,包括验证条件以避免已处理的记录,然后在 RepositoryItemReader 中使用该方法。

      应该是这样的

      @Query("SELECT r FROM Records r WHERE r.isNew = 1")
      Collection<Record> findAllNewRecords();
      

      然后像这样配置阅读器

      RepositoryItemReader<Record> recordsReader = new RepositoryItemReader<>();
      recordsReader.setRepository(recordsRepository);
      recordsReader.setMethodName("findAllNewRecords");
      

      希望对你有帮助

      【讨论】:

        【解决方案4】:
        create table T_UNIQUE_VALUE( a number,b number, c varchar2(100));
        
        alter table T_UNIQUE_VALUE ADD CONSTRAINT C_UNIQUE_VALUE UNIQUE (a,b);
        

        定义日志错误表。 Oralce 将创建err$_table_name

        BEGIN 
           DBMS_ERRLOG.create_error_log(dml_table_name => 'T_UNIQUE_VALUE'); 
        END;
        

        测试一下。

        execut 2 times  
        insert into  T_UNIQUE_VALUE values(1,1,'a')  LOG ERRORS REJECT LIMIT UNLIMITED;
        
        --check table T_UNIQUE_VALUE and  err$_T_UNIQUE_VALUE
        select * from err$_T_UNIQUE_VALUE; -- 1 row 
        select * from T_UNIQUE_VALUE;  -- 1 row
        

        修改spring注解。

        @Modifying
        @Query(value = "insert into  T_UNIQUE_VALUE values(:a,:b,:c)  LOG ERRORS REJECT LIMIT UNLIMITED",  nativeQuery = true)
        void insert_balbla(...)
        

        【讨论】:

          猜你喜欢
          • 2015-02-12
          • 1970-01-01
          • 2017-11-03
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2021-05-20
          • 2015-04-18
          • 1970-01-01
          相关资源
          最近更新 更多