Database 如何在回滚时使用Oracle DB序列而不丢失下一个序列号

Database 如何在回滚时使用Oracle DB序列而不丢失下一个序列号,database,oracle,sequence,Database,Oracle,Sequence,问题 如何在回滚时使用Oracle DB序列而不丢失下一个序列号 收集的事实 1-在Oracle中,我们可以创建一个序列,并使用两个主调用(NEXTVAL)来获取下一个序列值和(CURRVAL)来获取当前序列值 2-当我们呼叫(NEXTVAL)时,我们总是会得到下一个号码,如果出现回滚,我们将丢失该号码。换句话说,Oracle序列不关心是否存在回滚或提交;无论何时你呼叫它,它都会给出一个新号码 到目前为止我找到的可能答案 1-我正在考虑创建一个简单的表,其中包含一列类型(NUMBER)以满足此目

问题

如何在回滚时使用Oracle DB序列而不丢失下一个序列号

收集的事实

1-在Oracle中,我们可以创建一个序列,并使用两个主调用(
NEXTVAL
)来获取下一个序列值和(
CURRVAL
)来获取当前序列值

2-当我们呼叫(
NEXTVAL
)时,我们总是会得到下一个号码,如果出现回滚,我们将丢失该号码。换句话说,Oracle序列不关心是否存在回滚或提交;无论何时你呼叫它,它都会给出一个新号码

到目前为止我找到的可能答案

1-我正在考虑创建一个简单的表,其中包含一列类型(NUMBER)以满足此目的。 只需选择值并使用它。如果操作成功,我将增加列值。否则,我将在下次应用程序调用时保持原样

2-我在这里找到的另一种方法()是,如果我想后退一步,可以像下面那样使用(
ALTER SEQUENCE

也就是说,如果序列是101,我可以通过

ALTER SEQUENCE serial INCREMENT BY -1;
SELECT serial.NEXTVAL FROM dual;
ALTER SEQUENCE serial INCREMENT BY 1;
结论


是否有任何建议的解决方案是好的?他们有更好的方法吗?

在我看来,你应该使用顺序,不要再担心差距

从你的观点来看,我认为改变序列比拥有一张桌子更糟糕。请注意,对该表的访问必须限制为单个用户,否则,如果两个(或多个)用户同时访问该表,您将获得重复的值

下面是一个示例代码;看一看,如果你想使用/调整它

SQL> create table broj (redni_br number not null);

Table created.

SQL>
SQL> create or replace function f_get_broj
  2     return number
  3  is
  4     pragma autonomous_transaction;
  5     l_redni_br   broj.redni_br%type;
  6  begin
  7         select b.redni_br + 1
  8           into l_redni_br
  9           from broj b
 10     for update of b.redni_br;
 11
 12     update broj b
 13        set b.redni_br = l_redni_br;
 14
 15     commit;
 16     return (l_redni_br);
 17  exception
 18     when no_data_found
 19     then
 20        lock table broj in exclusive mode;
 21
 22        insert into broj (redni_br)
 23             values (1);
 24
 25        commit;
 26        return (1);
 27  end f_get_broj;
 28  /

Function created.

SQL> select f_get_broj from dual;

F_GET_BROJ
----------
         1

SQL> select f_get_broj from dual;

F_GET_BROJ
----------
         2

SQL>

在我看来,你应该使用一个序列,不要再担心间隔

从你的观点来看,我认为改变序列比拥有一张桌子更糟糕。请注意,对该表的访问必须限制为单个用户,否则,如果两个(或多个)用户同时访问该表,您将获得重复的值

下面是一个示例代码;看一看,如果你想使用/调整它

SQL> create table broj (redni_br number not null);

Table created.

SQL>
SQL> create or replace function f_get_broj
  2     return number
  3  is
  4     pragma autonomous_transaction;
  5     l_redni_br   broj.redni_br%type;
  6  begin
  7         select b.redni_br + 1
  8           into l_redni_br
  9           from broj b
 10     for update of b.redni_br;
 11
 12     update broj b
 13        set b.redni_br = l_redni_br;
 14
 15     commit;
 16     return (l_redni_br);
 17  exception
 18     when no_data_found
 19     then
 20        lock table broj in exclusive mode;
 21
 22        insert into broj (redni_br)
 23             values (1);
 24
 25        commit;
 26        return (1);
 27  end f_get_broj;
 28  /

Function created.

SQL> select f_get_broj from dual;

F_GET_BROJ
----------
         1

SQL> select f_get_broj from dual;

F_GET_BROJ
----------
         2

SQL>

您可以创建一个序列表

CREATE TABLE SEQUENCE_TABLE
  (SEQUENCE_ID NUMBER, 
   SEQUENCE_NAME VARCHAR2(30 BYTE), 
   LAST_SEQ_NO NUMBER);
在PL/SQL块中,您可以使用以下代码行获得序列

declare
    CURSOR c1 IS
       SELECT last_seq_no
         FROM sequence_table
        WHERE sequence_id = 21
          FOR UPDATE NOWAIT;
       v_last_seq_no NUMBER;
       v_new_seq_no NUMBER;
    resource_busy EXCEPTION;
    PRAGMA EXCEPTION_INIT(resource_busy, -54);
BEGIN
    LOOP
        BEGIN
           OPEN c1;
           FETCH c1 INTO v_last_seq_no;
           CLOSE c1;
           v_new_seq_no := v_last_seq_no+1;
           EXIT;
        EXCEPTION
            WHEN resource_busy THEN
                NULL;
                --or something you want to happen
        END;
   END LOOP;
   --after the this line, you can put an update to the sequence table and be sure to commit/rollback at the end of the pl/sql block;
END;
/


ROLLBACK;
--or
COMMIT;

试着在两个oracle会话中运行上面的PL/SQL代码以理解。基本上,如果Oracle DB会话1将运行代码,则从游标查询的记录将被锁定。因此,如果其他会话将运行相同的代码,则该会话将等待会话1的回滚/提交完成代码的运行。通过这种方式,两个会话将不会具有相同的序列。\u否,如果出于某些原因发出回滚,您可以选择不更新序列。

您可以创建序列表

CREATE TABLE SEQUENCE_TABLE
  (SEQUENCE_ID NUMBER, 
   SEQUENCE_NAME VARCHAR2(30 BYTE), 
   LAST_SEQ_NO NUMBER);
在PL/SQL块中,您可以使用以下代码行获得序列

declare
    CURSOR c1 IS
       SELECT last_seq_no
         FROM sequence_table
        WHERE sequence_id = 21
          FOR UPDATE NOWAIT;
       v_last_seq_no NUMBER;
       v_new_seq_no NUMBER;
    resource_busy EXCEPTION;
    PRAGMA EXCEPTION_INIT(resource_busy, -54);
BEGIN
    LOOP
        BEGIN
           OPEN c1;
           FETCH c1 INTO v_last_seq_no;
           CLOSE c1;
           v_new_seq_no := v_last_seq_no+1;
           EXIT;
        EXCEPTION
            WHEN resource_busy THEN
                NULL;
                --or something you want to happen
        END;
   END LOOP;
   --after the this line, you can put an update to the sequence table and be sure to commit/rollback at the end of the pl/sql block;
END;
/


ROLLBACK;
--or
COMMIT;
试着在两个oracle会话中运行上面的PL/SQL代码以理解。基本上,如果Oracle DB会话1将运行代码,则从游标查询的记录将被锁定。因此,如果其他会话将运行相同的代码,则该会话将等待会话1的回滚/提交完成代码的运行。通过这种方式,两个会话将不会具有相同的序列。\u no,并且如果出于某些原因发出回滚,您可以选择不更新序列