目标:在存储过程中实现返回一个流水号的生产单号(并发情况下如何产生)
规则:字母(1-5位)+日期(8位)+'-'+流水号(4位)
例子:A20090501-0001
A20090501-0002
A20090502-0001
A20090502-0002
A20090502-0003
A20090503-0001
B20090503-0001
B20090503-0002
基础设置表1
单据类别 字母 当前最大值 当前日期
销售单 A 1 20090503
采购单 B 2 20090503如何生成:销售单 销售单号请问各位高手,用存储过程如何实现呢.(提出有建设性的意见都有分)
是否可以不用设置基础也可以实现的呢 (比较急,谢谢!~)
规则:字母(1-5位)+日期(8位)+'-'+流水号(4位)
例子:A20090501-0001
A20090501-0002
A20090502-0001
A20090502-0002
A20090502-0003
A20090503-0001
B20090503-0001
B20090503-0002
基础设置表1
单据类别 字母 当前最大值 当前日期
销售单 A 1 20090503
采购单 B 2 20090503如何生成:销售单 销售单号请问各位高手,用存储过程如何实现呢.(提出有建设性的意见都有分)
是否可以不用设置基础也可以实现的呢 (比较急,谢谢!~)
最简单的,建一个序列好了,每次都去取序列号就可以了! 例子:A20090501-序列号-0001
A20090501-序列号-0002
A20090502-序列号-0001
A20090502-序列号-0002
A20090502-序列号-0003
A20090503-序列号-0001
B20090503-序列号-0001
B20090503-序列号-0002
一般的应用来说,锁是oracle自动控制的,你开发的时候,记得事务同步就可以了,别的不用考虑的。
给你个例子
CREATE TABLE TBL_MC_SEQ_CTL(
SEQ_GEN_CD CHAR(2) NOT NULL,
BUSS_ELE_DESC VARCHAR2(50) DEFAULT ' ' NOT NULL,
GBL_SEQ_NO NUMBER(15, 0) DEFAULT 0 NOT NULL,
SEQ_LENTH_QTY NUMBER(2, 0) DEFAULT 0 NOT NULL,
MIN_SEQ_NO NUMBER(15, 0) DEFAULT 0 NOT NULL,
MAX_SEQ_NO NUMBER(15, 0) DEFAULT 0 NOT NULL,
CYC_FLG CHAR(1) NOT NULL,
REG_USER_ID CHAR(10) DEFAULT ' ' NOT NULL,
UPD_USER_ID CHAR(10) DEFAULT ' ' NOT NULL,
REG_TMS TIMESTAMP(6) DEFAULT to_date('19000101000000','YYYYMMDDHH24MISS') NOT NULL,
UPD_ONLINE_TMS TIMESTAMP(6) DEFAULT to_date('19000101000000','YYYYMMDDHH24MISS') NOT NULL,
UPD_BATCH_TMS TIMESTAMP(6) DEFAULT to_date('19000101000000','YYYYMMDDHH24MISS') NOT NULL,
DEL_TMS TIMESTAMP(6) DEFAULT to_date('19000101000000','YYYYMMDDHH24MISS') NOT NULL,
DEL_FLG CHAR(1) NOT NULL
)
PCTFREE 5
PCTUSED 80
TABLESPACE MASTER_DATA
STORAGE(INITIAL 64K
NEXT 64K
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
)
;CREATE UNIQUE INDEX PK_MC_SEQ_CTL ON TBL_MC_SEQ_CTL(SEQ_GEN_CD, BUSS_ELE_DESC)
TABLESPACE MASTER_IDX
STORAGE(INITIAL 64K
NEXT 64K
MINEXTENTS 1
MAXEXTENTS UNLIMITED
PCTINCREASE 0
)
;
update 基础设置表1 set 当前最大值 = 当前最大值 +1 where... return 当前最大值 into ..., 而且这样做你想要的并发就由oracle来控制了,不需要你考虑了。
建个序列号表
create table TBL_SEQ
(
seq_type varchar2(5) not null,
current_date varchar2(8) not null,
current_value number(4,0) not null
);
写个取序列号的函数
create or replace function f_get_serial(pi_seq_type in varchar2)
return varchar2 is
Result varchar2(40);
vc_nowdate varchar2(8);
vc_seq_date varvhar2(8);
vn_value;
pragma autonomous_transaction;--自治事务,可以减少锁表的时间,提高并发能力
begin
select to_char(sysdate,'YYYYMMDD') into vc_nowdate from dual;--取当前日期
update tbl_seq --序列号+1,同时锁住该条记录
set current_value=current_value+1
where seq_type=pi_seq_type
returning current_value ,current_date into vn_value,vc_seq_date;
;
if vc_seq_date<vc_nowdate then --如果序列号表中的日期比当前日期小,重置序列号,更新日期,这时候该条记录已经锁住,不用担心并发问题
update tbl_seq
set current_value=1,
current_date=vc_nowdate
where seq_type=pi_seq_type
returning current_value ,current_date into vn_value,vc_seq_date;
;
end if;
Result :=pi_seq_type||vc_seq_date||'-'||lpad(to_char(vn_value),4,'0');
commit;--自治事务必须提交或回滚
return Result ;
end;
vn_value ;应该为 vn_value number;
通过这几个对oracle写锁与读锁的初步了解.应用过程中确认不用去并发问题(一般的应用来说,锁是oracle自动控制的,你开发的时候,记得事务同步就可以了,别的不用考虑的。正如:oraclelogan 所说的)1.如果通过使用序列的话(任务中每天调度一次,重置为零),引申出一个问题就是如果过程的事务回滚后,就会浪费序列号,导致业务单据号产生断号(当然断号情况排除业务单号被删除的例外情况),但如何才能既能使用序列,又能避免断号情况.
(因为我想用序列也许在并发情况下,效率也许会高过自身维护一个流水号值)2.设置基础表来维护流水号值,是否在并发情况下会慢些呢.不知有没有人对比测试过呢.3.从第一个问题产生另一个问题,如果每种单据都设置一个序列,那么又如何在一个存储过程中实现对多个序列进行重置呢.(这个疑问在网上找了,但没有收获,不知有没有人也有这种需求)
R:一个简单例子
create sequence seq_1 increment by 1 start with 1 maxvalue 999999999;
create or replace procedure P_TOOLS_RESET_SEQUENCES
(
pi_sequence_name in varchar2
)
as
vn_number number;
vr_sequence user_sequences%rowtype;
begin
-- Modify the last number
select * into vr_sequence from user_sequences t where t.sequence_name=pi_sequence_name;
if vr_sequence.max_value-vr_sequence.last_number>0 then
execute immediate 'alter sequence '||pi_sequence_name||' increment by '||(vr_sequence.max_value-vr_sequence.last_number)|| ' nocache';
execute immediate 'select '||pi_sequence_name||'.nextval from dual' into vn_number;
execute immediate 'alter sequence '||pi_sequence_name||' increment by 1 nocache';
execute immediate 'select '||pi_sequence_name||'.nextval from dual' into vn_number;
end if;
exception
when others then
null;
end P_TOOLS_RESET_SEQUENCES;