通过数据库中的函数、存储过程、游标、触发器等对象,结合数据库的内置函数(包括字符串函数、数字函数、日期函数、转换函数、正则表达式函数、聚合函数),将一些数据在数据库中进行处理后,再将其传到后端开发,对数据进行进一步处理,从而减少后端的开发量,有效提高系统的运行速度和性能。
特色:通过存储过程间接调用游标;后台定时执行存储过程
系统介绍
基于Java的银行ATM系统,使用客户端/服务器(C/S)的开发模式,根据不同的用户需求,把用户分为两种,分别是管理员和普通用户。
管理员能够根据不同的业务,修改相应的银行卡数据,同时保证操作的正确性,还能够及时查看历史数据,便于分析用户需求。在用户注册银行卡后,管理员能根据单据在数据库中添加客户信息,实现信息的长期存储。 此外,管理员通过系统能够及时分析用户的信息,在存款和贷款到期时,自动修改银行卡数据,减少不必要的损失。其中,管理员与普通用户共用同一主界面,当点击“查询详情”,系统查询用户身份,如果是管理员,则可查询存取款、贷款、转账、通信缴费、账户信息;而普通用户只能进行基本的银行卡操作,不可查询其他信息。
普通用户可以使用ATM实现存款、取款、贷款、查询明细、转账、销户等操作。其中,修改信息包括修改密码、手机号和身份证有效期,能够保证银行卡的正常使用。
兑换货币:所有用户均可使用该功能,其中,各种外币汇率是通过判断语句来获取汇率,再计算出兑换总额。
数据库设计
person(用户表)
card(银行卡表)
Trade(交易表)
数据库对象及代码
1.序列
给trade表的orderId列设置序列,实现自增
create sequence se_id start with 1 increment by 1;
2.触发器
trade表的orderId列实现自增
create or replace trigger tri_se_id
--在每次插入数据前执行触发器
before insert on trade for each row
--声明输入参数、输出参数
declare next_no number;
begin
--查询序列中下一个id,并存在next_no中
select se_id.nextval into next_no from dual;
--递归,更新编号
:new.orderId:=next_no;
end;
/
3. 函数
(1)查询用户的身份证有效期,查看证件是否有效
--a的数据类型与card表account列的相同
create or replace function fact(a in card.account%type)
--设置函数返回值
return number
as
--声明用到的参数
n number;
d person.idDate%type;
begin
--设置n的初始值
n:=1;
--查询idDate将其存在d中
select idDate into d from person join card on card.phone=person.phone where account=a;
--当身份证有效期早于当前日期时,返回0(sysdate查询当前日期)
if d<sysdate then
n:=0;
end if;
return(n);
commit;
end fact;
(2)查询银行卡是否在金苑银行办理
create or replace function bankto(a in card.account%type)
return number
as
b card.bank%type;
n number;
begin
select bank into b from card where account=a;
if b='金苑银行' then
n:=1;
else
n:=0;
end if;
return(n);
commit;
end bankto;
4. 游标
存储过程可以直接进行变量的设计并在后续直接调用,但游标不能直接由后端调用,它只能被放在存储过程里面利用存储过程定义的变量和存储过程一起被调用;或者可以设定定期运行的游标,在设定的时间里准时运行。
(1)存款到期时,自动添加利息到银行卡,并添加交易记录。
declare
cursor trade_curso is select * from trade where type='存款'
and biao='1' for update;//标记未加钱的存款
begin
--进入游标查询的每一行数据
for t in trade_curso loop
--当存款到期日期等于当前日期时,更新数据,current of trade_curso表示当前游标所处的行
if to_char(t.c_date,'yyyy')=to_char(sysdate,'yyyy') then
update card set money=money+t.fee where account=t.account;
update trade set biao='0' where current of trade_curso;//清除存款标记
--插入交易记录
insert into trade(account,type,fee) values (t.account,'存款利息',t.fee);
else
update trade set biao='1' where current of trade_curso;
end if;
end loop;
commit;
end;
(2)每个账户每月1号从卡里扣除2元的固定卡费,并添加交易记录
create or replace procedure youbiaoo
as
y card.account%type;
--查询并更新所有银行卡数据
cursor cardfee_cursor is select * from card for update;
begin
for r in cardfee_cursor loop
--银行卡余额>0
if r.money>0 then
--当前在每月1日时
if to_char(sysdate,'dd')='01' then
--修改当前行的余额
update card set money=money–2 where current of cardfee_cursor;
--查询修改后的余额
select money into y from card where account=r. account;
--插入交易记录
insert into trade(account,type,fee,yue) values(r.account,'卡费',2,y);
end if;
end if;
end loop;
commit;
end;
5.存储过程
定时执行存储过程
create or replace procedure time
as
j number;
begin
//每个月第一天的午夜12点执行
dbms_job.submit(j,'youbiaoo;', sysdate, 'TRUNC(LAST_DAY(SYSDATE ) + 1)');
commit;
end;
(1)添加取款记录
(2)注册时,先判断该手机号是否已注册,如果是,直接把账号等信息插入到card表;如果不是,先插入手机号到person 表,再插入信息到card表
create or replace procedure zhuCe(
a in card.account%type,
pw in card.pwd%type,
t in card.phone%type
)
as
p int;
i int;
begin
--查询当前手机号是否保存在person表
select count(*) into p from person where phone=t;
--该用户已注册
if p>0 then
insert into card(account,pwd,role,phone) values (a,pw,'1',t);
--未注册
elsif p=0 then
--插入用户信息
insert into person(phone) values(t);
--插入银行卡信息
insert into card(account,pwd,role,phone) values (a,pw,'1',t);
end if;
commit;
end;
(3)在新用户注册后,管理员把新用户的基本信息插入到person表
(4)在进行手机号或身份证有效期修改时,能够判断修改类型,并判断用户输入的姓名和身份证号是否正确,如果正确,就修改相应信息。
(5)查询该银行卡是否属于金苑银行,并判断证件是否有效,如果是,则修改余额,添加记录;如果不是,则不予办理。
(6)取款时,从卡里扣除相应金额
(7)注销时,判断用户当前是否还有未完成的贷款或存款业务,如果有,则不予办理;如果无,则从card表中删除账户
(8)根据输入的业务类型,查询总共的交易条数
(9)判断证件是否有效,如果有效,则办理存款,向卡里添加金额
(10)转账时,判断对方的银行卡是否属于本银行,如果是,直接办理转账;如果不是,需要额外扣除手续费
(11)登录时,判断身份是管理员还是普通用户
系统连接并操作数据库
以修改信息功能为例,用户可修改银行卡密码、身份证有效期、手机号,在修改时,需要输入相应信息,进行身份验证。
Class.forName("oracle.jdbc.driver.OracleDriver");
Connection conn = null;
//连接数据库
conn = DriverManager.getConnection("jdbc:oracle:thin:@127.0.0.1:1521:orcl", "scott", "***");
//执行数据库对象的方法
CallableStatement p2=null;
p2=conn.prepareCall("{call yan(?,?,?,?,?,?)}");
p2.setString(1, currCard.getAccount());
p2.setString(2, n1);
p2.setString(3, n);
p2.setString(4, "手机号");
p2.setString(5, t);
p2.registerOutParameter(6, Types.INTEGER);
p2.execute();
//获得数据库传回的数值
int m=p2.getInt(6);
if(m==1)
{pw.write("ok\r\n");pw.flush();}
else if (m==0)
{pw.write("false\r\n");pw.flush();}
//查询数据库数据
String sql2 = "select count(*) from trade where account='" +currCard.getAccount()
+ "'";
String sql1 = "select account,type,changeMoney,inTime,yuE from trade where account='" +currCard.getAccount()
+"' order by inTime desc";
ResultSet rs;
String a;
rs = st.executeQuery(sql2);rs.next();
//获取查询结果
pw.write(rs.getInt(1)+"\r\n");pw.flush();
rs = st.executeQuery(sql1);rs.next();