Oracle03——游标、异常、存储过程、存储函数、触发器和Java代码访问Oracle对象
作者: kent鹏
转载请注明出处: http://www.cnblogs.com/xieyupeng/p/7476717.html
1.游标(光标)Cursor
在写java程序中有集合的概念,那么在pl/sql中也会用到多条记录,这时候我们就要用到游标,游标可以存储查询返回的多条数据。
语法:
CURSOR 游标名 [ (参数名 数据类型,参数名 数据类型,...)] IS SELECT 语句;
例如:cursor c1 is select ename from emp;
游标的使用步骤:
- 打开游标: open c1; (打开游标执行查询)
- 取一行游标的值:fetch c1 into pjob; (取一行到变量中)
- 关闭游标: close c1;(关闭游标释放资源)
- 游标的结束方式 exit when c1%notfound
- 注意: 上面的pjob必须与emp表中的job列类型一致:
定义:pjob emp.empjob%type;
光标属性:%isopen %rowcount(影响的行数) %found %notfound
范例1:使用游标方式输出emp表中的员工编号和姓名
declare
cursor pc is
select * from emp;
pemp emp%rowtype;
begin
open pc;
loop
fetch pc
into pemp;
exit when pc%notfound;
dbms_output.put_line(pemp.empno || ' ' || pemp.ename);
end loop;
close pc;
end;
范例2:写一段PL/SQL程序,为部门号为10的员工涨工资。
declare
cursor pc(dno myemp.deptno%type) is
select empno from myemp where deptno = dno;
pno myemp.empno%type;
begin
open pc(20);
loop
fetch pc
into pno;
exit when pc%notfound;
update myemp t set t.sal = t.sal + 1000 where t.empno = pno;
end loop;
close pc;
end;
2.异常
异常是程序设计语言提供的一种功能,用来增强程序的健壮性和容错性。
系统定义异常
no_data_found (没有找到数据)
too_many_rows (select …into语句匹配多个行)
zero_divide ( 被零除)
value_error (算术或转换错误)
timeout_on_resource (在等待资源时发生超时)
范例1:写出被0除的异常的plsql程序
declare
pnum number;
begin
pnum := 1 / 0;
exception
when zero_divide then
dbms_output.put_line('被0除');
when value_error then
dbms_output.put_line('数值转换错误');
when others then
dbms_output.put_line('其他错误');
end;
用户也可以自定义异常,在声明中来定义异常
DECLARE My_job char(10); v_sal emp.sal%type; No_data exception; cursor c1 is select distinct job from emp order by job;
如果遇到异常我们要抛出raise no_data;
范例2:查询部门编号是50的员工
declare
no_emp_found exception;
cursor pemp is
select t.ename from emp t where t.deptno = 50;
pename emp.ename%type;
begin
open pemp;
fetch pemp
into pename;
if pemp%notfound then
raise no_emp_found;
end if;
close pemp;
exception
when no_emp_found then
dbms_output.put_line('没有找到员工');
when others then
dbms_output.put_line('其他错误');
end;
3.存储过程
存储过程(Stored Procedure)是在大型数据库系统中,一组为了完成特定功能的SQL 语句集,经编译后存储在数据库中,用户通过指定存储过程的名字并给出参数(如果该存储过程带有参数)来执行它。存储过程是数据库中的一个重要对象,任何一个设计良好的数据库应用程序都应该用到存储过程。
创建存储过程语法:
create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)]
AS
begin
PLSQL子程序体;
End;
或者
create [or replace] PROCEDURE 过程名[(参数名 in/out 数据类型)]
is
begin
PLSQL子程序体;
End 过程名;
范例1:给指定的员工涨100工资,并打印出涨前和涨后的工资
分析:我们需要使用带有参数的存储过程
create or replace procedure addSal1(eno in number) is
pemp myemp%rowtype;
begin
select * into pemp from myemp where empno = eno;
update myemp set sal = sal + 100 where empno = eno;
dbms_output.put_line('涨工资前' || pemp.sal || '涨工资后' || (pemp.sal + 100));
end addSal1;
调用
begin -- Call the procedure addsal1(eno => 7902); commit; end;
4.存储函数
create or replace function 函数名(Name in type, Name out type, ...) return 数据类型 is 结果变量 数据类型; begin return(结果变量); end[函数名];
存储过程和存储函数的区别
一般来讲,过程和函数的区别在于函数可以有一个返回值;而过程没有返回值。
但过程和函数都可以通过out指定一个或多个输出参数。我们可以利用out参数,在过程和函数中实现返回多个值。
范例:使用存储函数来查询指定员工的年薪
create or replace function empincome(eno in emp.empno%type) return number is psal emp.sal%type; pcomm emp.comm%type; begin select t.sal into psal from emp t where t.empno = eno; return psal * 12 + nvl(pcomm, 0); end;
使用存储过程来替换上面的例子
create or replace procedure empincomep(eno in emp.empno%type, income out number) is psal emp.sal%type; pcomm emp.comm%type; begin select t.sal, t.comm into psal, pcomm from emp t where t.empno = eno; income := psal*12+nvl(pcomm,0); end empincomep;
调用:
declare income number; begin empincomep(7369, income); dbms_output.put_line(income); end;
5.触发器
数据库触发器是一个与表相关联的、存储的PL/SQL程序。每当一个特定的数据操作语句(Insert,update,delete)在指定的表上发出时,Oracle自动地执行触发器中定义的语句序列。
1.触发器作用
l 数据确认
l 实施复杂的安全性检查
l 做审计,跟踪表上所做的数据操作等
l 数据的备份和同步
2.触发器的类型
语句级触发器 :在指定的操作语句操作之前或之后执行一次,不管这条语句影响 了多少行 。
行级触发器(FOR EACH ROW) :触发语句作用的每一条记录都被触发。在行级触 发器中使用old和new伪记录变量, 识别值的状态。
语法:
CREATE [or REPLACE] TRIGGER 触发器名
{BEFORE | AFTER}
{DELETE | INSERT | UPDATE [OF 列名]}
ON 表名
[FOR EACH ROW [WHEN(条件) ] ]
declare
……
begin
PLSQL 块
End 触发器名
范例:插入员工后打印一句话“一个新员工插入成功”
create or replace trigger testTrigger
after insert on person
declare
-- local variables here
begin
dbms_output.put_line('一个员工被插入');
end testTrigger;
范例:不能在休息时间插入员工
create or replace trigger validInsertPerson
before insert on person
declare
weekend varchar2(10);
begin
select to_char(sysdate, 'day') into weekend from dual;
if weekend in ('星期一') then
raise_application_error(-20001, '不能在非法时间插入员工');
end if;
end validInsertPerson;
当执行插入时会报错
在触发器中触发语句与伪记录变量的值
|
触发语句 |
:old |
:new |
|
Insert |
所有字段都是空(null) |
将要插入的数据 |
|
Update |
更新以前该行的值 |
更新后的值 |
|
delete |
删除以前该行的值 |
所有字段都是空(null) |
范例:判断员工涨工资之后的工资的值一定要大于涨工资之前的工资
create or replace trigger addsal4p
before update of sal on myemp
for each row
begin
if :old.sal >= :new.sal then
raise_application_error(-20002, '涨前的工资不能大于涨后的工资');
end if;
end;
调用
update myemp t set t.sal = t.sal - 1;
3.触发器实际应用
需求:使用序列,触发器来模拟mysql中自增效果
1. 创建序列
1、建立表
复制代码 代码如下:
create table user (
id number(6) not null,
name varchar2(30) not null primary key
)
2、建立序列SEQUENCE
代码如下:
create sequence user_seq increment by 1 start with 1 minvalue 1 maxvalue 9999999999999 nocache order;
2.创建自增的触发器
分析:创建一个基于该表的before insert 触发器,在触发器中使用刚创建的SEQUENCE。
代码如下:
create or replace trigger user_trigger
before insert on user
for each row
begin
select user_seq.nextval into:new.id from sys.dual ;
end;
3.测试效果
insert into itcastuser(name) values('aa');
commit;
insert into itcastuser(name) values('bb');
commit;
5.Java代码访问Oracle对象
1.java连接oracle的jar包
可以在虚拟机中xp的oracle安装目录下找到jar包 :ojdbc14.jar
2.数据库连接字符串
String driver="oracle.jdbc.OracleDriver"; String url="jdbc:oracle:thin:@192.168.56.10:1521:orcl"; String username="scott"; String password="tiger";
测试代码:

3.实现过程与函数的调用
1.调用过程
1.过程定义
--统计年薪的过程 create or replace procedure proc_countyearsal(eno in number,esal out number) as begin select sal*12+nvl(comm,0) into esal from emp where empno=eno; end; --调用 declare esal number; begin proc_countyearsal(7839,esal); dbms_output.put_line(esal); end;
2.过程调用
@Test
public void testProcedure01() { String driver = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl"; String username = "scott"; String password = "tiger"; try { Class.forName(driver); Connection con = DriverManager.getConnection(url, username, password); CallableStatement callSt = con.prepareCall("{call proc_countyearsal(?,?)}"); callSt.setInt(1, 7839); callSt.registerOutParameter(2, OracleTypes.NUMBER); callSt.execute(); System.out.println(callSt.getObject(2)); } catch (Exception e) { e.printStackTrace(); } }
2.调用函数
1.函数定义
--统计年薪的函数 create or replace function fun_countyearsal(eno in number) return number as esal number:=0; begin select sal*12+nvl(comm,0) into esal from emp where empno=eno; return esal; end; --调用 declare esal number; begin esal:=fun_countyearsal(7839); dbms_output.put_line(esal); end;
2.函数调用
@Test
public void testFunction01() { String driver = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl"; String username = "scott"; String password = "tiger"; try { Class.forName(driver); Connection con = DriverManager.getConnection(url, username, password); CallableStatement callSt = con.prepareCall("{?= call fun_countyearsal(?)}"); callSt.registerOutParameter(1, OracleTypes.NUMBER); callSt.setInt(2, 7839); callSt.execute(); System.out.println(callSt.getObject(1)); } catch (Exception e) { e.printStackTrace(); } }
4.游标引用的java测试
1.定义过程,并返回引用型游标
--定义过程
create or replace procedure proc_cursor_ref(dno in number,empList out sys_refcursor)
as
begin
open empList for select * from emp where deptno = dno;
end;
--pl/sql中调用
declare
mycursor_c sys_refcursor;
myempc emp%rowtype;
begin
proc_cursor_ref(20,mycursor_c);
loop
fetch mycursor_c into myempc;
exit when mycursor_c%notfound;
dbms_output.put_line(myempc.empno||','||myempc.ename);
end loop;
close mycursor_c;
end;
2.java代码调用游标类型的out参数
@Test
public void testFunction() { String driver = "oracle.jdbc.OracleDriver"; String url = "jdbc:oracle:thin:@192.168.56.10:1521:orcl"; String username = "scott"; String password = "tiger"; try { Class.forName(driver); Connection con = DriverManager.getConnection(url, username, password); CallableStatement callSt = con.prepareCall("{call proc_cursor_ref (?,?)}"); callSt.setInt(1, 20); callSt.registerOutParameter(2, OracleTypes.CURSOR); callSt.execute(); ResultSet rs = ((OracleCallableStatement) callSt).getCursor(2); while (rs.next()) { System.out.println(rs.getObject(1) + "," + rs.getObject(2)); } } catch (Exception e) { e.printStackTrace(); } }
Oracle03——游标、异常、存储过程、存储函数、触发器和Java代码访问Oracle对象的更多相关文章
- Oracle数据库游标,序列,存储过程,存储函数,触发器
游标的概念: 游标是SQL的一个内存工作区,由系统或用户以变量的形式定义.游标的作用就是用于临时存储从数据库中提取的数据块.在某些情况下,需要把数据从存放在磁盘的表中调到计算机内存中进行处理, ...
- Oracle学习2 视图 索引 sql编程 游标 存储过程 存储函数 触发器
---视图 ---视图的概念:视图就是提供一个查询的窗口,来操作数据库中的数据,不存储数据,数据在表中. ---一个由查询语句定义的虚拟表. ---查询语句创建表 create table emp a ...
- PL/SQL&存储过程||存储函数&触发器
plsql 有点:交互式 非过程化 数据操纵能力强 自动导航语句简单 调试简单 想率高 声明类型的方式 1.基本类型 2.引用变量 3.记录型变量 基本格式 declare 声明 b ...
- Oracle学习(十二):存储过程/存储函数
1.知识点 --第一个存储过程 /* 打印Hello World create [or replace] PROCEDURE 过程名(參数列表) AS PLSQL子程序体: 调用存储过程: 1. ex ...
- oracle存储过程和存储函数&触发器
oracle存储过程和存储函数 指存储在数据库中供所有用户程序调用的子程序叫存储过程,存储函数 存储过程和存储函数的相同点:完成特定功能的程序 存储过程和存储函数的区别:是否用return语句返回值 ...
- PL/SQL 编程(二)游标、存储过程、函数
游标--数据的缓存区 游标:类似集合,可以让用户像操作数组一样操作查询出来的数据集,实质上,它提供了一种从集合性质的结果中提取单条记录的手段. 可以将游标形象的看成一个变动的光标,他实质上是一个指针, ...
- oracle 存储过程,存储函数,包,
http://heisetoufa.iteye.com/blog/366957 认识存储过程和函数 存储过程和函数也是一种PL/SQL块,是存入数据库的PL/SQL块.但存储过程和函数不同于已经介绍过 ...
- Java代码调用Oracle的存储过程,存储函数和包
Java代码调用存储过程和存储函数要使用CallableStatement接口 查看API文档: 上代码: java代码调用如下的存储过程和函数: 查询某个员工的姓名 月薪 职位 create or ...
- mybatis中调用游标,存储过程,函数
在ibatis和Mybatis对存储过程和函数函数的调用的配置Xml是不一样的,以下是针对Mybatis 3.2的环境进行操作的. 第一步配置Mapper的xml内容 <mapper names ...
随机推荐
- 还在为CSS布局发愁?你该看看这7条原则
一.网页结构分析七条原则 这以下7个原则是经过多年网站实战经验之后的总结,只要掌握这7个原则,可以解决大部分在编写网站布局中的问题. 1.先结构后样式. 2.能用CSS表现出来的效果,就尽量少用图像. ...
- [COGS 1752] 摩基亚Mokia
照例先上题面 1752. [BOI2007]摩基亚Mokia 输入文件:mokia.in 输出文件:mokia.out 时间限制:1.5 s 内存限制:128 MB [题目描述] 摩尔瓦多的移 ...
- 【.net 深呼吸】自定义应用程序配置节
实际上,应用程序配置文件 App.config,是由各个节(Configuration Section)组成的,通常,配置节是按功能划分的,比如我们很熟悉的 appSettings.connectio ...
- ue4 C++ 编程 通过三个点的位置算出夹角
const FVector2D& Pt1 = 第一个点的位置; const FVector2D& Pt2 = 第二个点的位置; float EdgeRadians1 = FMath:: ...
- Appium实现的技巧
截图功能: //截屏并保存至本地 File screen = driver.getScreenshotAs(OutputType.FILE); File ...
- 甲方VS乙方
甲方与乙方,在很多人都存在有误解,不知道究竟如何辨别.这里我提一些简单的辨别方式:甲方一般是指提出目标的一方,在合同拟订过程中主要是提出要实现什么目标,乙方一般是指完成目标,在合同中主要是提出如何保证 ...
- Python Class System
1.序言 本文旨在说明:在Python里自定义class时,方法的第一个参数必须是该class的instance自身的引用(一般用self命名). 在其他语言里,定义方法的时候,第一个参数不必是类实例 ...
- C# 调用 C++ DLL方法
在C# 中,可以通过 DllImport 调用C++ 的非托管DLL程序. VS2010中C#调用C++的DLL示例: 一.新建C++ DLL程序 1.新建 C++ Win32项目,类型为DLL. 生 ...
- WEB测试常见BUG
翻页 翻页时,没有加载数据为空,第二页数据没有请求 翻页时,重复请求第一页的数据 翻页时,没有图片的内容有时候会引用有图片的内容 2.图片数据为空 图片数据为空时,会保留为空的图片数据位置 ...
- asp.net core MVC 过滤器之ActionFilter过滤器(二)
本系类将会讲解asp.net core MVC中的内置全局过滤器的使用,将分为以下章节 asp.net core MVC 过滤器之ExceptionFilter过滤器(一) asp.net core ...