Mam zdefiniowaną sekwencję Oracle:
CREATE SEQUENCE "DALLAS"."X_SEQ"
MINVALUE 0
MAXVALUE 999999999999999999999999999
INCREMENT BY 1 START WITH 0 NOCACHE NOORDER NOCYCLE ;
Jest używany w procedurze przechowywanej do wstawienia rekordu:
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;
Czasami ta procedura zwraca błąd po uruchomieniu z kodu aplikacji.
ORA-01400: cannot insert NULL into ("DALLAS"."X"."THE_ID")
ORA-06512: at "DALLAS.X_PKG", line 40
ORA-06512: at line 1
Szczegóły, które mogą, ale nie muszą być istotne:
- Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Produkcja 64-bitowa
- Procedura jest wykonywana za pośrednictwem Microsoft.Practices.EnterpriseLibrary - Data.Oracle.OracleDatabase.ExecuteReader (polecenie DbCommand)
- Aplikacja nie zawija połączenia w jawną transakcję.
- Wkładka nie działa sporadycznie - mniej niż 1%
W jakich okolicznościach może x_seq.nextval
być zerowy?
v_id
odnosi się tylko do wyboru sekwencji, wstawki i kursora końcowego. Naszym następnym krokiem było dodanie kodu debugującego. Być może będziemy musieli czekać na wyniki, ponieważ zdarza się to tylko w produkcji i bardzo rzadko. Istnieje wyzwalacz, który wstawia się do tabeli kontroli. Przeczesałem go bez palącego pistoletu. Problem czasami pojawia się także w innych tabelach bez wyzwalaczy. Dzięki za obejrzenie.Odpowiedzi:
Jestem pewien, że skończy się to artefaktem twojego kodu lub sterownika .net, którego używasz. Przygotowałem dla ciebie szybkie demo, używając czystego SQL - PL / SQL i nigdy nie otrzymałem utraconej wartości sekwencji. Nawiasem mówiąc, kursor ref, którego używasz, jest prawdopodobnie niepotrzebny i prawdopodobnie wpływa na wydajność i czytelność kodu - moje demo zawiera procedurę insert_record2, która konsekwentnie wykonuje ponad 10% szybciej - około 26 sekund na moim laptopie w porównaniu z 36 w przypadku wersji kursora ref. Przynajmniej uważam, że łatwiej to zrozumieć. Możesz oczywiście uruchomić zmodyfikowaną wersję dla testowej bazy danych wraz z wyzwalaczem kontroli.
źródło
:new.the_id
jest nietknięty. Rozumiem, że moje pytanie jest dalekie. Jest odporny na moje google-fu i tutaj kilka osób drapie się po głowach. Właśnie pomyślałem, że ktoś może rozpoznać objaw (i leczenie), mając wystarczającą liczbę gałek ocznych. Dzięki za obejrzenie.Spróbuj zrobić przypadek testowy. Zrób tabelę zastępczą i wstaw 100 000 rekordów, używając sekwencji z bazy danych. Założę się, że nie będziesz mieć problemów. Następnie spróbuj wstawić to samo z aplikacji.
Czy może to być spowodowane innymi problemami, takimi jak niedopasowanie klienta Oracle?
Innym rozwiązaniem, które rozwiązałoby problem, ale nie stanowi problemu, jest dodanie wyzwalacza na stole.
Przed wstawieniem do tabeli w Dallas.X JEŻELI: identyfikator_i jest zerowy NASTĘPNIE WYBIERZ x_seq.nextval INTO: identyfikator_ID z dual; KONIEC JEŻELI;
źródło
Nie mam jeszcze uprawnień do komentowania, więc pisząc to jako odpowiedź: Ponieważ używasz wersji Oracle> = 11.1, która zezwala na sekwencje w wyrażeniach PL / SQL zamiast w SQL, spróbuj tego:
Zamiast tego:
Lub chociaż słyszałem wątpliwości / pułapki podczas używania „.currval”, może pomijam oddzielne przypisanie v_id i używam tylko tego kodu ?:
Przepraszam, nie mam teraz przydatnej instancji 11g, aby to wypróbować.
źródło
select into...
w 11 tyle, ile w 9i i 10g. Jedyną korzyścią płynącą z 11+ jest możliwość wyraźnego odwołania się do niej, jak już wskazałeś.