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