悟心

          成功不是將來才有的,而是從決定去做的那一刻起,持續(xù)累積而成。 上人生的旅途罷。前途很遠(yuǎn),也很暗。然而不要怕。不怕的人的面前才有路。

            BlogJava :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
            93 隨筆 :: 1 文章 :: 103 評論 :: 0 Trackbacks
          項(xiàng)目中需要使用到按規(guī)則生成序列號,開始的解決辦法是根據(jù)條件取得最大ID號進(jìn)行分解+1再合并的解決方案,后來發(fā)現(xiàn)如果兩個客戶同時操作的時候出現(xiàn)問題:添加的時候ID已經(jīng)存在,原因是:A用戶在訪問取得第MAX(N)記錄deID,但是還沒有進(jìn)行增加操作,這時,B用戶也取得第MAX(N)記錄deID,這是A進(jìn)行添加操作同時,B也同時進(jìn)行添加操作,那么B用戶就會保存失敗,我們開始的時候采用的解決方案是:(枷鎖)在程序的方法上枷鎖,采用單線程操作,實(shí)施結(jié)果:失敗,客戶等待時間長,后來我們采用綁定數(shù)據(jù)庫的方案:編寫存儲過程,雖然綁定不怎么方便,但是執(zhí)行效率要快很多。由于時間問題,沒有做序列自動創(chuàng)建功能,歡迎各位大蝦進(jìn)行指點(diǎn)和評論,我們最后的方案如下:
          在oracle里面編寫了2個基本做基本處理的自定義函數(shù):
          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; --為處理打開光標(biāo)
            DBMS_SQL.PARSE(v_curId, v_Sql, DBMS_SQL.native); --分析語句
            DBMS_SQL.DEFINE_COLUMN(v_curId, 1, p_table, 128); --定義動態(tài)游標(biāo)所能得到的對應(yīng)值
            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); --執(zhí)行語句

            loop
              
          if DBMS_SQL.FETCH_ROWS(v_curId) = 0 then
                
          exit;
              
          end if;
              DBMS_SQL.COLUMN_VALUE(v_curId, 
          1, p_table); --將所取得的游標(biāo)數(shù)據(jù)賦值到相應(yīng)的變量
              --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); 
          --關(guān)閉一個動態(tài)游標(biāo)
            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)
          /**
          * 流水帳號創(chuàng)建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;

          下面為調(diào)用實(shí)例:
          select fun_config_glide_num('TabMachineType','FAC_CODE'as CN FROM dual;

          下面是表流水帳號表結(jié)構(gòu)

          -- Create table
          create table LSZH_TABLE
          (
            LSZH_CNAME    
          CHAR(20not null,
            LSZH_TNAME    
          CHAR(20),
            LSZH_COLUMN   
          CHAR(20not null,
            LSZH_MARK     
          CHAR(20),
            LSZH_DATETYPE 
          CHAR(10),
            LSZH_NUM      
          CHAR(3default 4
          )

          -- Add comments to the columns 
          comment on column LSZH_TABLE.LSZH_CNAME
            
          is '流水帳號類名';
          comment 
          on column LSZH_TABLE.LSZH_TNAME
            
          is '流水帳對應(yīng)的數(shù)據(jù)庫表名';
          comment 
          on column LSZH_TABLE.LSZH_COLUMN
            
          is '流水帳號類別標(biāo)識列';
          comment 
          on column LSZH_TABLE.LSZH_MARK
            
          is '流水帳號類別標(biāo)識對應(yīng)的字符';
          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系統(tǒng)包提供了很多函數(shù)及過程,現(xiàn)在簡要闡述其中使用頻率較高的幾種:   
              
            function   open_cursor:打開一個動態(tài)游標(biāo),并返回一個整型;   
              
            procedure   close_cursor(c   in   out   integer);關(guān)閉一個動態(tài)游標(biāo),參數(shù)為open_cursor所打開的游標(biāo);   
              
            procedure   parse(c   in   integer,   statement   in   varchar2,   language_flag   in   integer):對動態(tài)游標(biāo)所提供的sql語句進(jìn)行解析,參數(shù)C表示游標(biāo),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]):定義動態(tài)游標(biāo)所能得到的對應(yīng)值,其中c為動態(tài)游標(biāo),positon為對應(yīng)動態(tài)sql中的位置(從1開始),column為該值所對應(yīng)的變量,可以為任何類型,column_size只有在column為定義長度的類型中使用如VARCHAR2,CHAR等(該過程有很多種情況,此處只對一般使用到的類型進(jìn)行表述);   
              
            function   execute(c   in   integer):執(zhí)行游標(biāo),并返回處理一個整型,代表處理結(jié)果(對insert,delete,update才有意義,而對select語句而言可以忽略);   
              
            function   fetch_rows(c   in   integer):對游標(biāo)進(jìn)行循環(huán)取數(shù)據(jù),并返回一個整數(shù),為0時表示已經(jīng)取到游標(biāo)末端;   
              
            procedure   column_value(c   in   integer,   position   in   integer,   value):將所取得的游標(biāo)數(shù)據(jù)賦值到相應(yīng)的變量,c為游標(biāo),position為位置,value則為對應(yīng)的變量;   
              
            procedure   bind_variable(c   in   integer,   name   in   varchar2,   value):定義動態(tài)sql語句(DML)中所對應(yīng)字段的值,c為游標(biāo),name為字段名稱,value為字段的值;   
              
            以上是在程序中經(jīng)常使用到的幾個函數(shù)及過程,其他函數(shù)及過程請參照oracle所提供定義語句dbmssql.sql   
              
              
            對于一般的select操作,如果使用動態(tài)的sql語句則需要進(jìn)行以下幾個步驟:   
            open   cursor--->parse--->define   column--->excute--->fetch   rows--->close   cursor;   
            而對于dml操作(insert,update)則需要進(jìn)行以下幾個步驟:   
            open   cursor--->parse--->bind   variable--->execute--->close   cursor;   
            對于delete操作只需要進(jìn)行以下幾個步驟:   
            open   cursor--->parse--->execute--->close   cursor;   
          序列sequence:
          http://www.examda.com/Oracle/
          關(guān)于Oracle的序列(Sequence)使用序列是一數(shù)據(jù)庫對象,利用它可生成唯一的整數(shù)。一般使用序列自動地生成主鍵值。對我們程序員來講,精力時間有限,我們只學(xué)最有用的知識。大家請看:
            
          1) 建立序列命令
            
          CREATE SEQUENCE [user.]sequence_name
            
          [increment by n]
            
          [start with n]
            
          [maxvalue n | nomaxvalue]
            
          [minvalue n | nominvalue];
            
          [NOCYCLE]  --
            INCREMENT BY: 指定序列號之間的間隔,該值可為正的或負(fù)的整數(shù),但不可為0.序列為升序。忽略該子句時,缺省值為1.
            START 
          WITH:指定生成的第一個序列號。在升序時,序列可從比最小值大的值開始,缺省值為序列的最小值。對于降序,序列可由比最大值小的值開始,缺省值為序列的最大值。
            MAXVALUE:指定序列可生成的最大值。
            NOMAXVALUE:為升序指定最大值為1027,為降序指定最大值為
          -1.
            MINVALUE:指定序列的最小值。
            NOMINVALUE:為升序指定最小值為1.為降序指定最小值為
          -1026.
            NOCYCLE:一直累加,不循環(huán)
            
          2) 更改序列命令
            ALTERSEQUENCE 
          [user.]sequence_name
            
          [INCREMENT BY n]
            
          [MAXVALUE n| NOMAXVALUE ]
            
          [MINVALUE n | NOMINVALUE];
            修改序列可以:修改未來序列值的增量。
            設(shè)置或撤消最小值或最大值。
            改變緩沖序列的數(shù)目。
            指定序列號是否是有序。
            注意:
            
          1,第一次NEXTVAL返回的是初始值
            
          2,可以alter除start至以外的所有sequence參數(shù)。如果想要改變start值,必須 drop sequence 再 re-create .
            
          3) 刪除序列命令
            
          DROP SEQUENCE [user.]sequence_name;
            用于從數(shù)據(jù)庫中刪除一序列。
            
          4)牛刀小試
            
          4.1)創(chuàng)建一個序列號的語句:
            
          -- 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);
          參考資料鏈接:
          關(guān)于DBMS_SQL包,動態(tài)SQL語句的問題
          oracle 隱式游標(biāo),顯示游標(biāo),游標(biāo)循環(huán),動態(tài)SELECT語句和動態(tài)游標(biāo),異常處理,自定義異常
          oracle 創(chuàng)建,刪除存儲過程,參數(shù)傳遞,創(chuàng)建,刪除存儲函數(shù),存儲過程和函數(shù)的查看,包,系統(tǒng)包
          幾種使用動態(tài)SQL做游標(biāo)的總結(jié)
          關(guān)于動態(tài)SQL的使用
          oracle創(chuàng)建存儲過程
          oracle創(chuàng)建函數(shù),存儲過程,視圖以及for循環(huán)語法
          oracle自定義函數(shù)
          posted on 2010-02-24 17:20 艾波 閱讀(4542) 評論(2)  編輯  收藏 所屬分類: SQL

          評論

          # re: Oracle 游標(biāo)總結(jié)+整理 2010-02-24 17:52 石頭JAVA擺地攤兒
          貼主,能講一講原理嗎?

          代碼太多沒有看懂,

          這個是怎么實(shí)現(xiàn)的?什么原理?

            回復(fù)  更多評論
            

          # re: Oracle 游標(biāo)總結(jié)+整理 2010-03-06 23:57 spdia
          為什么不用 oracle sequence實(shí)現(xiàn)主鍵  回復(fù)  更多評論
            

          主站蜘蛛池模板: 霍邱县| 大姚县| 奉化市| 永年县| 长治县| 土默特左旗| 瑞昌市| 嵊州市| 临洮县| 安福县| 永胜县| 兴化市| 扬州市| 奉节县| 徐汇区| 虞城县| 安顺市| 临安市| 乌审旗| 偃师市| 利辛县| 蚌埠市| 宁武县| 元朗区| 图木舒克市| 崇文区| 贵定县| 辉县市| 高淳县| 印江| 宁明县| 岳西县| 江川县| 文成县| 荥经县| 洞头县| 焦作市| 内乡县| 昭平县| 临洮县| 天镇县|