将Oracle序列增加一定量

时间:2011-07-01 13:30:36

标签: oracle session plsql

我正在编写一个Windows应用程序(在Qt 4.6中) - 在某些时候 - 将1到76000之间的任意数量的数据集插入到某个oracle(10.2)表中。应用程序必须从序列中检索主键或至少主键范围。然后,它会将ID存储在一个列表中,该列表用于批处理执行准备好的查询。

(注意:不应使用触发器,序列也由其他任务使用)

为了避免调用序列X次,我想用X递增序列。

到目前为止,我发现以下代码是可行的:

ALTER SEQUENCE my_sequence INCREMENT BY X;

SELECT my_sequence.CURVAL + 1, my_sequence.NEXTVAL
INTO   v_first_number, v_last_number
FROM   dual;

ALTER SEQUENCE my_sequence INCREMENT BY 1;

我有两个主要问题:

  1. 我已经读过ALTER SEQUENCE产生一个隐式提交。这是否意味着Windows应用程序启动的事务将被提交?如果是这样,你能以某种方式避免它吗?
  2. 这个概念是多用户证明吗?或者可能发生以下事情:

    Sequence is at 10,000
    Session A sets increment to 2,000
    Session A selects 10,001 as first and 12,000 as last
    Session B sets increment to 5,000
    Session A sets increment to 1
    Session B selects 12,001 as first and 12,001 as last
    Session B sets increment to 1
    

    即使程序相当快,但在我的应用程序中,两个不同的用户几乎不能同时调用该过程并不是那么不可能

4 个答案:

答案 0 :(得分:5)

1)ALTER SEQUENCE是DDL,因此它在语句之前和之后隐式提交。将提交由Windows应用程序启动的数据库事务。如果您使用的是Oracle数据库以外的分布式事务协调器,那么希望事务协调器将提交整个分布式事务,但事务协调器有时会发出它不知道的提交问题。   您无法阻止DDL提交。

2)您可以使用多个用户概述的方案。因此,听起来这种方法在您的环境中表现不正确。

您可以使用DBMS_LOCK包来确保只有一个会话在任何时间点调用您的过程,然后从单个SQL语句中调用该序列N次。但是如果其他进程也在使用序列,则无法保证您将获得一组连续的值。

CREATE PROCEDURE some_proc( p_num_rows IN NUMBER,
                            p_first_val OUT NUMBER,
                            p_last_val  OUT NUMBER )
AS
  l_lockhandle       VARCHAR2(128);
  l_lock_return_code INTEGER;
BEGIN
  dbms_lock.allocate_unique( 'SOME_PROC_LOCK',
                             l_lockhandle );
  l_lock_return_code := dbms_lock.request( lockhandle => l_lockhandle,
                                           lockmode => dbms_lock.x_mode,
                                           release_on_commit => true );
  if( l_lock_return_code IN (0, 4) ) -- Success or already owned
  then
    <<do something>>
  end if;

  dbms_lock.release( l_lockhandle );
END; 

答案 1 :(得分:4)

在这种情况下改变序列是非常糟糕的主意。特别是在多用户环境中。您将提交您的事务,可能还有几个“竞争条件”数据错误或完整性错误。 如果您已导入旧数据并且希望使用序列中的ID插入新数据,那将是合适的。然后你可以改变序列以将currval移动到max existing ...

在我看来,你想在这里生成序列中的ID。

不需要这样做
select seq.nextval into l_variable from dual;
insert into table (id, ...) values (l_variable, ....);

您可以直接在插入中使用序列:

insert into table values (id, ...) values (seq.nextval, ....);

并可选择通过

获取指定的值
insert into table values (id, ...) values (seq.nextval, ....)
returning id into l_variable;

甚至可以使用execBatch进行批量操作。要么只是创建ID,要么甚至返回它们。我不确定java中的正确语法,但它将是关于行的内容

insert into table values (id, ...) values (seq.nextval, ....)
returning id bulk collect into l_cursor;

并且您将获得一个ResultSet来浏览指定的数字。

答案 2 :(得分:2)

  1. 您无法阻止隐式提交。

  2. 您的解决方案不是多用户证明。正如您所描述的那样,完全有可能另一个会话将增量“恢复”为1。

  3. 我建议您继续从序列中逐个获取值,将这些ID逐个存储在列表中,并让批处理执行在该列表上。

    您想从序列中获取连续值块的原因是什么?我不会太担心性能,但也许还有其他我不知道的要求。

答案 3 :(得分:2)

在Oracle中,您可以使用以下查询从递增1的序列中获取下一个N值:

选择级别,PDQ_ACT_COMB_SEQ.nextval作为来自双级连接的seq&lt; = 5;