项目中需要使用到按规则生成序列号,开始的解决办法是根据条件取得最大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自定义函数