oracle存储过程和触发器结合项目详细讲解
2013-11-19 09:28
183 查看
项目名:“学生公寓型床位出租管理系统”
业务逻辑:
情形1:床位出租,就是按床位出租而不是按一个房间来算的,一个房间有固定的床位,有4个6个8个不等的床位,一般这种床位房都是一月一交,也就可以算成30天就得交一次房租。当有租客来入住,我首先要查询有空床位的房间,有空床位就办理入住,就填入租客入住信息。另外租客入住进去后,这个房间的床位就要减少一个,所以需要建立两个表房间表(room)和租客信息表(customer),房间表里有房间号(roomid),房间总床位(sumnum),房间剩余床位(renum),所以房间表就是room(roomid
char, sumnum int, renum int),另外有个问题就是比如房间号908有四个床位,现在都住满人了,在插入一个新租客我就不能让他插入,那该怎么控制呢?后面会讲到
情形2:那入住的时候,租客信息表里应有哪些内容呢?首先毋庸置疑,租客姓名(cname),租客所在房间号(roomid),入住时间(paydate)是必须存在的。仅仅这些行吗?显然这几个字段和room表里的字段仅仅只能完成选择房间,不能完成交费,到期提醒,到期欠交费相关逻辑。
情形3:那么现在就有这样一个问题摆在面前,比如一租客小强已经入住了,怎么记录他已入住的天数(daycounts),这里如果在java程序中可以用线程定义一个定时器,每一天已入住天数就要加1则daycounts=daycounts+1,在oracle中job中也可以实现定时器功能后面会讲到。
情形4:假如小强下个月房租15号到期,一般要在到期前3天提醒交房租,所以现在租客表里就需要一个到期提醒字段,也就是增加一个快到期天数(recounts)来记录,当recounts<=3就要提醒。现在新问题又出现了,快到期了租客就要交房租如果到期后租客没交房租,那应该怎么查出欠交房租的租客了?那么租客表里就要设立一个字段交费状态(paystate)来标明已交和欠交费的用户,如果paystate=0就表示欠交,如果paystate=1就表示已交费,那么在java程序中租客信息展示页面就有个“交费”按钮,一点击交费,paystate就设置为1了。
情形5:想想情形4中有没有问题?问题1:虽然在情形4中点交费只能交一个月的房租,因为情形1中已经说明一般是30天交一次房租,但假如情况特殊,有的租客一下子需要交两个月甚至三个月,那怎么控制。问题2:当小强交了房租后,我点击“交费”paystate=1,下一次他到期后还要交房租,因为现在paystate=1显示他已经交了就不用交了,房东肯定受不了。所以这里30天小强房租再次到期后还要将paystate变为0。问题三:假设小强房租是10月10号到期,因其它原因小强拖欠了一个月房租,一直到11月10号才交了上一个月拖欠的房租,但现在要交房租啊,总要记录,点击交费后,paystate=1显示小强已经交了房租,但实际还拖欠1个月房租,只把10月10号交了,11月10号还没交只是房东要哭了。这里paystate就不能是boolean类型的,paystate就只能为int类型代表月数,1就是交了1月,2就是交了2月,0就是没交,到期后paystate就要减1,比如小强一下交了3个月房租,到期后他没交房租,paystate-1=2,表示他还剩2个月房租,在情形3中天数每天都在自动加1,daycounts=daycounts+1,到期后天数就要归为0,到期的天数就是paystate*30,也就是到期天数=paystate*30时,同时paystate>0才能将daycounts更新为0。程序其实非常简单,主要是搞清业务逻辑。
综合上述两个表设计为:
表设计:
customer(cid()
int, cname(姓名) char, roomid(房间号) char, paydate(入住时间) date, paystate(月数) int, datecounts(入住天数) int, recounts(到期天数) int)租客表
[sql]
view plaincopyprint?
create table CUSTOMER
(
cid VARCHAR2(8) not null,
cname VARCHAR2(6),
roomid NUMBER(6),
paydate DATE,
paystate NUMBER(4),
datecounts NUMBER(5) default 0,
recounts NUMBER(4)
)
tablespace DONCOD
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 16
next 8
minextents 1
maxextents unlimited
);
[sql]
view plaincopyprint?
create table ROOM
(
roomid VARCHAR2(8) not
null,
sumnum NUMBER(6),
renum NUMBER(6)
)
tablespace DONCOD
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 16
next 8
minextents 1
maxextents unlimited
);
业务解决:
解决情形1中问题,用触发器是最合适的。
[sql]
view plaincopyprint?
create orreplacetrigger CUSINFO
before insert on customer--表示在customer表里创建触发器,并在插入前触发
for each row --表示行级别触发
declare
v_num number; --声明总床位变量
v_count number; --声明对应房间号住的人数
begin
--:new.roomid表示新插入租客的roomid号
select sumnum into v_numfrom roomwhere roomid = :new.roomid;
--给v_count变量赋值
select count(*)into v_countfrom customerwhere
roomid = :new.roomid;
if (v_num - v_count) < 0
then
--解决情形1中不让插入的问题
delete from customerwhere cid = :new.cid;
else
--解决情形1中自动计算剩余床位的问题
update room
set renum =
(v_num - v_count - 1)
where roomid = :new.roomid;
end if;
end CUSINFO;
解决情形4和情形5用存储过程
[sql]
view plaincopyprint?
create orreplaceprocedure payfei(pid customer.cid%type)as
--声明变量pays,%type表示pays和paystate同类型,相当于paystate包含pays
pays customer.paystate%type;
dat customer.datecounts%type;
rec customer.recounts%type;
begin
--给上面定义的变量赋值
select paystate, datecounts, recounts
into pays, dat, rec
from customer
where cid = pid;--这里防止返回的结果集越界
update customer
--天数加1,主要解决情形5中的问题
set datecounts = datecounts + 1,
recounts = paystate * 30 - datecounts - 1;
if rec = 0 and pays > 0
then
update customer set datecounts = 0, paystate = paystate - 1;
end if;
end;
解决情形3定时器的问题
[sql]
view plaincopyprint?
create orreplaceprocedure TIMERas
job number;
begin
--dbms_job是oracle的系统包
dbms_job.submit(JOB => job,
WHAT => 'PAYFEI(1);',--表示要调用的存储过程
next_date => sysdate,
interval => 'sysdate+60/(24*60*60)');--表示一分钟执行一次
--由于一天执行一次效果太慢,所以为了观察方便就搞成一分钟执行一次,下面是一天执行一次
--next_date=>to_date('15-11-2013 15:40:00','dd-mm-yyyy hh24:mi:ss'),
--interval => 'sysdate+1');
commit;
DBMS_JOB.RUN(job);
end TIMER;
实际运用:
上述都弄完了,现在在java程序中就变得非常简单。
1:查询空床位,查询剩余2张床位
select * from room where renum>0; select * from room where renum=2;
2:查询还有三天就要到期的租客
select * from customer where recounts=3;
3:查询欠费的租客
select * from customer where paystate<=0;
注意点:上面一个触发器和两个存储过程都要先编译下,测试的话就运行TIMER存储过程就行了
[sql]
view plaincopyprint?
begin timer; commit; end;
然后删除job定时器
[sql]
view plaincopyprint?
begin
dbms_job.remove("查询出来JOB列所对应的值,一般是数字");
commit;
end;
业务逻辑:
情形1:床位出租,就是按床位出租而不是按一个房间来算的,一个房间有固定的床位,有4个6个8个不等的床位,一般这种床位房都是一月一交,也就可以算成30天就得交一次房租。当有租客来入住,我首先要查询有空床位的房间,有空床位就办理入住,就填入租客入住信息。另外租客入住进去后,这个房间的床位就要减少一个,所以需要建立两个表房间表(room)和租客信息表(customer),房间表里有房间号(roomid),房间总床位(sumnum),房间剩余床位(renum),所以房间表就是room(roomid
char, sumnum int, renum int),另外有个问题就是比如房间号908有四个床位,现在都住满人了,在插入一个新租客我就不能让他插入,那该怎么控制呢?后面会讲到
情形2:那入住的时候,租客信息表里应有哪些内容呢?首先毋庸置疑,租客姓名(cname),租客所在房间号(roomid),入住时间(paydate)是必须存在的。仅仅这些行吗?显然这几个字段和room表里的字段仅仅只能完成选择房间,不能完成交费,到期提醒,到期欠交费相关逻辑。
情形3:那么现在就有这样一个问题摆在面前,比如一租客小强已经入住了,怎么记录他已入住的天数(daycounts),这里如果在java程序中可以用线程定义一个定时器,每一天已入住天数就要加1则daycounts=daycounts+1,在oracle中job中也可以实现定时器功能后面会讲到。
情形4:假如小强下个月房租15号到期,一般要在到期前3天提醒交房租,所以现在租客表里就需要一个到期提醒字段,也就是增加一个快到期天数(recounts)来记录,当recounts<=3就要提醒。现在新问题又出现了,快到期了租客就要交房租如果到期后租客没交房租,那应该怎么查出欠交房租的租客了?那么租客表里就要设立一个字段交费状态(paystate)来标明已交和欠交费的用户,如果paystate=0就表示欠交,如果paystate=1就表示已交费,那么在java程序中租客信息展示页面就有个“交费”按钮,一点击交费,paystate就设置为1了。
情形5:想想情形4中有没有问题?问题1:虽然在情形4中点交费只能交一个月的房租,因为情形1中已经说明一般是30天交一次房租,但假如情况特殊,有的租客一下子需要交两个月甚至三个月,那怎么控制。问题2:当小强交了房租后,我点击“交费”paystate=1,下一次他到期后还要交房租,因为现在paystate=1显示他已经交了就不用交了,房东肯定受不了。所以这里30天小强房租再次到期后还要将paystate变为0。问题三:假设小强房租是10月10号到期,因其它原因小强拖欠了一个月房租,一直到11月10号才交了上一个月拖欠的房租,但现在要交房租啊,总要记录,点击交费后,paystate=1显示小强已经交了房租,但实际还拖欠1个月房租,只把10月10号交了,11月10号还没交只是房东要哭了。这里paystate就不能是boolean类型的,paystate就只能为int类型代表月数,1就是交了1月,2就是交了2月,0就是没交,到期后paystate就要减1,比如小强一下交了3个月房租,到期后他没交房租,paystate-1=2,表示他还剩2个月房租,在情形3中天数每天都在自动加1,daycounts=daycounts+1,到期后天数就要归为0,到期的天数就是paystate*30,也就是到期天数=paystate*30时,同时paystate>0才能将daycounts更新为0。程序其实非常简单,主要是搞清业务逻辑。
综合上述两个表设计为:
表设计:
customer(cid()
int, cname(姓名) char, roomid(房间号) char, paydate(入住时间) date, paystate(月数) int, datecounts(入住天数) int, recounts(到期天数) int)租客表
[sql]
view plaincopyprint?
create table CUSTOMER
(
cid VARCHAR2(8) not null,
cname VARCHAR2(6),
roomid NUMBER(6),
paydate DATE,
paystate NUMBER(4),
datecounts NUMBER(5) default 0,
recounts NUMBER(4)
)
tablespace DONCOD
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 16
next 8
minextents 1
maxextents unlimited
);
create table CUSTOMER ( cid VARCHAR2(8) not null, cname VARCHAR2(6), roomid NUMBER(6), paydate DATE, paystate NUMBER(4), datecounts NUMBER(5) default 0, recounts NUMBER(4) ) tablespace DONCOD pctfree 10 initrans 1 maxtrans 255 storage ( initial 16 next 8 minextents 1 maxextents unlimited );room(roomid(房号) char, sumnum(总床位) int, renum(剩余床位) int) 房间表
[sql]
view plaincopyprint?
create table ROOM
(
roomid VARCHAR2(8) not
null,
sumnum NUMBER(6),
renum NUMBER(6)
)
tablespace DONCOD
pctfree 10
initrans 1
maxtrans 255
storage
(
initial 16
next 8
minextents 1
maxextents unlimited
);
create table ROOM ( roomid VARCHAR2(8) not null, sumnum NUMBER(6), renum NUMBER(6) ) tablespace DONCOD pctfree 10 initrans 1 maxtrans 255 storage ( initial 16 next 8 minextents 1 maxextents unlimited );
业务解决:
解决情形1中问题,用触发器是最合适的。
[sql]
view plaincopyprint?
create orreplacetrigger CUSINFO
before insert on customer--表示在customer表里创建触发器,并在插入前触发
for each row --表示行级别触发
declare
v_num number; --声明总床位变量
v_count number; --声明对应房间号住的人数
begin
--:new.roomid表示新插入租客的roomid号
select sumnum into v_numfrom roomwhere roomid = :new.roomid;
--给v_count变量赋值
select count(*)into v_countfrom customerwhere
roomid = :new.roomid;
if (v_num - v_count) < 0
then
--解决情形1中不让插入的问题
delete from customerwhere cid = :new.cid;
else
--解决情形1中自动计算剩余床位的问题
update room
set renum =
(v_num - v_count - 1)
where roomid = :new.roomid;
end if;
end CUSINFO;
create or replace trigger CUSINFO before insert on customer--表示在customer表里创建触发器,并在插入前触发 for each row --表示行级别触发 declare v_num number; --声明总床位变量 v_count number; --声明对应房间号住的人数 begin --:new.roomid表示新插入租客的roomid号 select sumnum into v_num from room where roomid = :new.roomid; --给v_count变量赋值 select count(*) into v_count from customer where roomid = :new.roomid; if (v_num - v_count) < 0 then --解决情形1中不让插入的问题 delete from customer where cid = :new.cid; else --解决情形1中自动计算剩余床位的问题 update room set renum = (v_num - v_count - 1) where roomid = :new.roomid; end if; end CUSINFO;
解决情形4和情形5用存储过程
[sql]
view plaincopyprint?
create orreplaceprocedure payfei(pid customer.cid%type)as
--声明变量pays,%type表示pays和paystate同类型,相当于paystate包含pays
pays customer.paystate%type;
dat customer.datecounts%type;
rec customer.recounts%type;
begin
--给上面定义的变量赋值
select paystate, datecounts, recounts
into pays, dat, rec
from customer
where cid = pid;--这里防止返回的结果集越界
update customer
--天数加1,主要解决情形5中的问题
set datecounts = datecounts + 1,
recounts = paystate * 30 - datecounts - 1;
if rec = 0 and pays > 0
then
update customer set datecounts = 0, paystate = paystate - 1;
end if;
end;
create or replace procedure payfei(pid customer.cid%type) as --声明变量pays,%type表示pays和paystate同类型,相当于paystate包含pays pays customer.paystate%type; dat customer.datecounts%type; rec customer.recounts%type; begin --给上面定义的变量赋值 select paystate, datecounts, recounts into pays, dat, rec from customer where cid = pid;--这里防止返回的结果集越界 update customer --天数加1,主要解决情形5中的问题 set datecounts = datecounts + 1, recounts = paystate * 30 - datecounts - 1; if rec = 0 and pays > 0 then update customer set datecounts = 0, paystate = paystate - 1; end if; end;
解决情形3定时器的问题
[sql]
view plaincopyprint?
create orreplaceprocedure TIMERas
job number;
begin
--dbms_job是oracle的系统包
dbms_job.submit(JOB => job,
WHAT => 'PAYFEI(1);',--表示要调用的存储过程
next_date => sysdate,
interval => 'sysdate+60/(24*60*60)');--表示一分钟执行一次
--由于一天执行一次效果太慢,所以为了观察方便就搞成一分钟执行一次,下面是一天执行一次
--next_date=>to_date('15-11-2013 15:40:00','dd-mm-yyyy hh24:mi:ss'),
--interval => 'sysdate+1');
commit;
DBMS_JOB.RUN(job);
end TIMER;
create or replace procedure TIMER as job number; begin --dbms_job是oracle的系统包 dbms_job.submit(JOB => job, WHAT => 'PAYFEI(1);',--表示要调用的存储过程 next_date => sysdate, interval => 'sysdate+60/(24*60*60)');--表示一分钟执行一次 --由于一天执行一次效果太慢,所以为了观察方便就搞成一分钟执行一次,下面是一天执行一次 --next_date=>to_date('15-11-2013 15:40:00','dd-mm-yyyy hh24:mi:ss'), --interval => 'sysdate+1'); commit; DBMS_JOB.RUN(job); end TIMER;
实际运用:
上述都弄完了,现在在java程序中就变得非常简单。
1:查询空床位,查询剩余2张床位
select * from room where renum>0; select * from room where renum=2;
2:查询还有三天就要到期的租客
select * from customer where recounts=3;
3:查询欠费的租客
select * from customer where paystate<=0;
注意点:上面一个触发器和两个存储过程都要先编译下,测试的话就运行TIMER存储过程就行了
[sql]
view plaincopyprint?
begin timer; commit; end;
begin timer; commit; end;定时器启动后会一直在后台运行,想关闭定时器先得查询job任务
SELECT * FROM Dba_Jobs查询出来后记录JOB列所对应的值
然后删除job定时器
[sql]
view plaincopyprint?
begin
dbms_job.remove("查询出来JOB列所对应的值,一般是数字");
commit;
end;
相关文章推荐
- android 项目的主要结构与详细讲解
- javaee实战项目--农贸产品开发(详细讲解及代码实现)
- Android项目智能机器人的实现,带有源代码,图灵智能机器人,详细讲解。。
- RabbitMQ与java、Spring结合实例详细讲解
- VS2010程序打包操作(结合图片详细讲解)
- OFBiz搭建项目详细讲解
- RabbitMQ与java、Spring结合实例详细讲解
- RabbitMQ与java、Spring结合实例详细讲解
- spring心得3--bean的生命周期结合案例详细讲解@普通期图解与uml图解一并分析
- 基于Dubbo协议的项目示例及详细讲解(二)
- 详细讲解有关Oracle存储过程的相关问题
- RabbitMQ与java、Spring结合实例详细讲解
- RabbitMQ与java、Spring结合实例详细讲解
- spring心得3--bean的生命周期结合案例详细讲解@普通期图解与uml图解一并分析
- AAA RabbitMQ与java、Spring结合实例详细讲解
- 《铁道部12306项目中的‘技术’》----财经杂志封面文章详细讲解
- Android中PopupWindow结合项目讲解
- 详细讲解如何用Cocos2dx3.0alpha0搭建跨平台项目,并通过cygwin部署android项目,并在eclipse打开。
- [置顶] Android项目智能机器人的实现,带有源代码,图灵智能机器人,详细讲解。。