在Spring批处理应用程序中从多个线程进行插入时,如何使用序列表确保oracle数据库中的顺序主键

时间:2017-07-05 06:56:51

标签: java oracle11g spring-batch

我有一个数据聚合和加载应用程序,可以将数据文件加载到oracle数据库。我们使用spring集成进行文件轮询和弹簧批处理以将数据加载到数据库。当处理多个文件(读取并加载到数据库)时,主键往往会跳过某些值。 创建的Oracle序列是。

CREATE SEQUENCE  "SCHEMA"."SEQUENCE_TABLE_NAME"  MINVALUE 1 MAXVALUE 
    9999999999999999999999999999 INCREMENT BY 1 START WITH 241488161 CACHE 
    20 NOORDER  NOCYCLE ;

入站通道适配器有一个轮询器,它具有任务执行器。入站通道适配器将文件发送到转换器,该转换器创建由作业启动网关启动的JobLaunchRequest对象。 该作业有一个阅读器和一个执行以下语句的jdbcwriter。

<bean id="itemWriter" class="org.springframework.batch.item.database.JdbcBatchItemWriter">
    <property name="dataSource" ref="dataSource"/>
    <property name="sql">
        <value>
            <![CDATA[
            insert  into data_table (id,dataA,dataB)
            values(SEQUENCE_TABLE_NAME.nextval,:dataA,:dataB)
            ]]>
        </value>
    </property>
    <property name="itemSqlParameterSourceProvider">
        <bean
             class="org.springframework.batch.item.database.BeanPropertyItemSqlParameterSourceProvider"/>
    </property>
</bean>

加载到数据库的关键原因是api暴露,这取决于订购和顺序的主键。但是一旦文件夹中出现两个很多文件。由于多线程读写db。序列表提供的主键缺少一些值。

A similar case is explained here (oracle perspective alone).

3 个答案:

答案 0 :(得分:0)

  

你应该创建一个自己的运行序列的实现   交易...

尝试这样的事情:

CREATE TABLE schema.sequence_table ( seq BIGINT );

INSERT
  INTO schema.sequence_table
  VALUES (0);

CREATE OR REPLACE
  FUNCTION get_next_seq()
  RETURN BIGINT
  AS
DECLARE
  s BIGINT;
BEGIN
  SELECT COALESCE(seq) + 1
    INTO s
    FROM schema.sequence_table;
  UPDATE schema.sequence_table
    SET seq = s;
  RETURN s;
END;

答案 1 :(得分:0)

恕我直言,如果您要求列中不存在间隙,则不应使用主键序列,因为主键必须在INSERT时间存在,如果交易后来中止你会得到一个空白。

一个简单的解决方案是拥有一个与主键不同的专用列,它将在单个线程(或专用的单线程应用程序)成功插入后更新。此任务将获取最近插入的行,例如当前序列值以上的主键减去阈值(如果表包含大量行,则加速请求)和专用列值为null,将它们连续分配值,提交和迭代。在最低负载时每天一次,任务应该获取专用列(非索引查询)上可能具有空值的所有行作为catch all pass。

答案 2 :(得分:-1)

首先通过API公开主键通常是一种不好的做法。

但这是另一个方法:

让所有线程在原始表中创建这些行,根本不关心主键。创建一个在原始表上具有外键引用的新表,以及用于存储顺序值的第二列。单个线程将连续从原始表中选取行,并使用序列在新表中创建行。然后将新表的顺序值公开为API中的键。

由于只有该线程正在访问序列,因此应该没有间隙。如果您不期望可以想象的单个线程应该能够处理多个其他线程的负载的最高负载。

在项目对您的API可见之前会引入延迟,因为现在涉及第二个交易。