項目中需要使用到按規則生成序列號,開始的解決辦法是根據條件取得最大ID號進行分解+1再合并的解決方案,后來發現如果兩個客戶同時操作的時候出現問題:添加的時候ID已經存在,原因是:A用戶在訪問取得第MAX(N)記錄deID,但是還沒有進行增加操作,這時,B用戶也取得第MAX(N)記錄deID,這是A進行添加操作同時,B也同時進行添加操作,那么B用戶就會保存失敗,我們開始的時候采用的解決方案是
:(枷鎖)在程序的方法上枷鎖,采用單線程操作,實施結果:失敗,客戶等待時間長,后來我們采用綁定數據庫的方案:編寫存儲過程,雖然綁定不怎么方便,但是執行效率要快很多。由于時間問題,沒有做序列自動創建功能,歡迎各位大蝦進行指點和評論,我們最后的方案如下:
在oracle里面編寫了2個基本做基本處理的自定義函數:
create or replace function fun_config_glide_num(p_class varchar2,
p_column varchar2)
/**
* 流水帳號配置_oracle
* author:ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定義開頭字符
*/
return varchar2 as
v_curId integer;
-- v_seq varchar2(50);
-- v_seq_value number;
v_sql varchar2(200);
v_ret number(3);
v_num varchar2(20);
p_table varchar2(30);
p_website varchar2(20);
p_length varchar2(3);
t_class varchar2(20);
t_column varchar2(20);
begin
t_class := p_class;
t_column := p_column;
v_sql := 'SELECT lszh_tname,lszh_mark,lszh_num FROM lszh_table WHERE lszh_cname = ' ||
chr(39) || t_class || chr(39) || '
and lszh_column=' || chr(39) || t_column || chr(39) || '';
v_curId := DBMS_SQL.OPEN_CURSOR; --為處理打開光標
DBMS_SQL.PARSE(v_curId, v_Sql, DBMS_SQL.native); --分析語句
DBMS_SQL.DEFINE_COLUMN(v_curId, 1, p_table, 128); --定義動態游標所能得到的對應值
DBMS_SQL.DEFINE_COLUMN(v_curId, 2, p_website, 128);
DBMS_SQL.DEFINE_COLUMN(v_curId, 3, p_length, 128);
v_ret := DBMS_SQL.EXECUTE(v_curId); --執行語句
loop
if DBMS_SQL.FETCH_ROWS(v_curId) = 0 then
exit;
end if;
DBMS_SQL.COLUMN_VALUE(v_curId, 1, p_table); --將所取得的游標數據賦值到相應的變量
--DBMS_OUTPUT.PUT_LINE(p_table);
DBMS_SQL.COLUMN_VALUE(v_curId, 2, p_website);
--DBMS_OUTPUT.PUT_LINE(p_website);
DBMS_SQL.COLUMN_VALUE(v_curId, 3, p_length);
--DBMS_OUTPUT.PUT_LINE(p_length);
end loop;
DBMS_SQL.CLOSE_CURSOR(v_curid); --關閉一個動態游標
v_num := fun_get_glide_num(trim(p_table), trim(p_website), trim(p_length));
return v_num;
end;
create or replace function fun_get_glide_num(p_table varchar2,p_website varchar2,p_length number)
/**
* 流水帳號創建oracle版本
* author : ai bo 2010.02.23
* p_table varchar2 表名
* p_website varchar2 自定義開頭字符
*/
return varchar2 as
v_seq varchar2(50);
v_seq_value number;
v_sql varchar2(200);
v_num varchar2(20);
begin
v_seq := 'seq_' || p_table;
v_sql := 'select ' || v_seq || '.nextval from dual';
dbms_output.put_line(v_sql);
execute immediate v_sql
into v_seq_value;
select lpad(v_seq_value, p_length, '0') into v_num from dual;
v_num := p_website || v_num;
return v_num;
end;
下面為調用實例:
select fun_config_glide_num('TabMachineType','FAC_CODE') as CN FROM dual;
下面是表流水帳號表結構
-- Create table
create table LSZH_TABLE
(
LSZH_CNAME CHAR(20) not null,
LSZH_TNAME CHAR(20),
LSZH_COLUMN CHAR(20) not null,
LSZH_MARK CHAR(20),
LSZH_DATETYPE CHAR(10),
LSZH_NUM CHAR(3) default 4
)

-- Add comments to the columns
comment on column LSZH_TABLE.LSZH_CNAME
is '流水帳號類名';
comment on column LSZH_TABLE.LSZH_TNAME
is '流水帳對應的數據庫表名';
comment on column LSZH_TABLE.LSZH_COLUMN
is '流水帳號類別標識列';
comment on column LSZH_TABLE.LSZH_MARK
is '流水帳號類別標識對應的字符';
comment on column LSZH_TABLE.LSZH_DATETYPE
is '時間作為流水號的排列次序';
comment on column LSZH_TABLE.LSZH_NUM
is '流水碼長度';
-- Create/Recreate primary, unique and foreign key constraints
alter table LSZH_TABLE
add constraint PK_LSZH_TABLE primary key (LSZH_COLUMN, LSZH_CNAME)

參考資料:
DBMS_SQL系統包提供了很多函數及過程,現在簡要闡述其中使用頻率較高的幾種:
function open_cursor:打開一個動態游標,并返回一個整型;
procedure close_cursor(c in out integer);關閉一個動態游標,參數為open_cursor所打開的游標;
procedure parse(c in integer, statement in varchar2, language_flag in integer):對動態游標所提供的sql語句進行解析,參數C表示游標,statement為sql語句,language-flag為解析sql語句所用oracle版本,一般有V6,V7跟native(在不明白所連database版本時,使用native);
procedure define_column(c in integer, position in integer, column any datatype, [column_size in integer]):定義動態游標所能得到的對應值,其中c為動態游標,positon為對應動態sql中的位置(從1開始),column為該值所對應的變量,可以為任何類型,column_size只有在column為定義長度的類型中使用如VARCHAR2,CHAR等(該過程有很多種情況,此處只對一般使用到的類型進行表述);
function execute(c in integer):執行游標,并返回處理一個整型,代表處理結果(對insert,delete,update才有意義,而對select語句而言可以忽略);
function fetch_rows(c in integer):對游標進行循環取數據,并返回一個整數,為0時表示已經取到游標末端;
procedure column_value(c in integer, position in integer, value):將所取得的游標數據賦值到相應的變量,c為游標,position為位置,value則為對應的變量;
procedure bind_variable(c in integer, name in varchar2, value):定義動態sql語句(DML)中所對應字段的值,c為游標,name為字段名稱,value為字段的值;
以上是在程序中經常使用到的幾個函數及過程,其他函數及過程請參照oracle所提供定義語句dbmssql.sql
對于一般的select操作,如果使用動態的sql語句則需要進行以下幾個步驟:
open cursor--->parse--->define column--->excute--->fetch rows--->close cursor;
而對于dml操作(insert,update)則需要進行以下幾個步驟:
open cursor--->parse--->bind variable--->execute--->close cursor;
對于delete操作只需要進行以下幾個步驟:
open cursor--->parse--->execute--->close cursor;

序列sequence:
http://www.examda.com/Oracle/
關于Oracle的序列(Sequence)使用序列是一數據庫對象,利用它可生成唯一的整數。一般使用序列自動地生成主鍵值。對我們程序員來講,精力時間有限,我們只學最有用的知識。大家請看:
1) 建立序列命令
CREATE SEQUENCE [user.]sequence_name
[increment by n]
[start with n]
[maxvalue n | nomaxvalue]
[minvalue n | nominvalue];
[NOCYCLE] --
INCREMENT BY: 指定序列號之間的間隔,該值可為正的或負的整數,但不可為0.序列為升序。忽略該子句時,缺省值為1.
START WITH:指定生成的第一個序列號。在升序時,序列可從比最小值大的值開始,缺省值為序列的最小值。對于降序,序列可由比最大值小的值開始,缺省值為序列的最大值。
MAXVALUE:指定序列可生成的最大值。
NOMAXVALUE:為升序指定最大值為1027,為降序指定最大值為-1.
MINVALUE:指定序列的最小值。
NOMINVALUE:為升序指定最小值為1.為降序指定最小值為-1026.
NOCYCLE:一直累加,不循環
2) 更改序列命令
ALTERSEQUENCE [user.]sequence_name
[INCREMENT BY n]
[MAXVALUE n| NOMAXVALUE ]
[MINVALUE n | NOMINVALUE];
修改序列可以:修改未來序列值的增量。
設置或撤消最小值或最大值。
改變緩沖序列的數目。
指定序列號是否是有序。
注意:
1,第一次NEXTVAL返回的是初始值
2,可以alter除start至以外的所有sequence參數。如果想要改變start值,必須 drop sequence 再 re-create .
3) 刪除序列命令
DROP SEQUENCE [user.]sequence_name;
用于從數據庫中刪除一序列。
4)牛刀小試
4.1)創建一個序列號的語句:
-- Create sequence
create sequence NCME_QUESTION_SEQ
minvalue 1
maxvalue 999999999999
start with 1
increment by 1
nocache;
//////////////////////////////
4.2)SQL中取序列號的用法:
SELECT NCME_QUESTION_SEQ.nextval FROM dual
SELECT NCME_QUESTION_SEQ.CURRVAL FROM dual
SELECT NCME_QUESTION_SEQ.nextval FROM dual SELECT NCME_QUESTION_SEQ.CURRVAL FROM dual
注意:在使用序列的時候,有時需要有用戶名,就像這樣:
insert into system.CONSERVATOR(CONSERVATORNAME,CONPASS,CONTRUENAME,CONSEX,CONID)values('JG','123456','000',0, system.CONID.nextval);
參考資料鏈接:
關于DBMS_SQL包,動態SQL語句的問題
oracle 隱式游標,顯示游標,游標循環,動態SELECT語句和動態游標,異常處理,自定義異常
oracle 創建,刪除存儲過程,參數傳遞,創建,刪除存儲函數,存儲過程和函數的查看,包,系統包
幾種使用動態SQL做游標的總結
關于動態SQL的使用
oracle創建存儲過程
oracle創建函數,存儲過程,視圖以及for循環語法
oracle自定義函數