在 Oracle 中,sequence.nextval 怎么可能为空?

Cor*_*rch 11 oracle sequence

我有一个像这样定义的 Oracle 序列:

CREATE SEQUENCE  "DALLAS"."X_SEQ"  
    MINVALUE 0 
    MAXVALUE 999999999999999999999999999 
    INCREMENT BY 1 START WITH 0 NOCACHE  NOORDER  NOCYCLE ;
Run Code Online (Sandbox Code Playgroud)

它在存储过程中用于插入记录:

PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT TYPES_PKG.RefCursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO X
            (the_id,            
             name,                        
             update_userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;
Run Code Online (Sandbox Code Playgroud)

有时,此过程在从应用程序代码执行时会返回错误。

ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID") 
ORA-06512: at "DALLAS.X_PKG", line 40 
ORA-06512: at line 1
Run Code Online (Sandbox Code Playgroud)

可能相关或不相关的详细信息:

  • Oracle 数据库 11g 企业版 11.2.0.1.0 版 - 64 位生产
  • 该过程通过 Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader(DbCommand command) 执行
  • 应用程序不会将调用包装在显式事务中。
  • 插入件间歇性失效 - 小于 1%

在什么情况下可以x_seq.nextval为空?

Nia*_*eld 4

我非常确定这最终将成为您的代码或您正在使用的 .net 驱动程序的产物。我已经使用纯 SQL - PL/SQL 为您制作了一个快速演示,并且永远不会丢失序列值。顺便说一句,您使用的引用光标可能是不必要的,并且可能会影响代码的性能和可读性 - 我的演示包括一个 insert_record2 过程,该过程始终快于 10% 以上 - 在我的笔记本电脑上大约需要 26 秒,而引用光标版本则需要 36 秒。至少我也认为更容易理解。显然,您可以针对带有审核触发器的测试数据库运行修改后的版本。

/* 
demo for dbse 
assumes a user with create table, create sequence, create procedure pivs and quota. 

*/

drop table dbse13142 purge;

create table dbse13142(
    the_id number not null
,   name   varchar2(20)
,   userid number)
;

drop sequence x_seq;
CREATE SEQUENCE  X_SEQ NOCACHE  NOORDER  NOCYCLE ;

create or replace PROCEDURE Insert_Record
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 cur_out   OUT sys_refcursor)
    IS
        v_id NUMBER := 0;
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO v_id
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (v_id,
             p_name,                        
             p_userid);

        -- Return new id
        OPEN cur_out FOR
            SELECT v_id the_id
              FROM dual;
    END;
/


create or replace PROCEDURE Insert_Record2
                (p_name    IN  VARCHAR2,                
                 p_userid  IN  INTEGER,
                 p_theid   OUT dbse13142.the_id%type)
    IS
    BEGIN
        -- Get id value from sequence
        SELECT x_seq.nextval
          INTO p_theid
          FROM dual;

        -- Line below is X_PKG line 40
        INSERT INTO dbse13142
            (the_id,            
             name,                        
             userid)
          VALUES
            (p_theid,
             p_name,                        
             p_userid);
    END;
/

set timing on

declare
   c sys_refcursor;
begin   
for i in 1..100000 loop
   insert_record('User '||i,i,c);
   close c;
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;

declare
  x number;
begin   
for i in 1..100000 loop
   insert_record2('User '||i,i,x);
end loop;
commit;
end;
/

select count(*) from dbse13142;
truncate table dbse13142;
Run Code Online (Sandbox Code Playgroud)