十三、存储过程和存储函数
1、掌握存储过程(相当于建立一个函数或者方法体,然后通过外部对其调用)
指存储在数据库中供所有程序调用的子程序叫做存储过程或存储函数。

相同点:
完成特定功能的程序
区别:
是否用return语句返回值

(1)创建和使用存储过程
用create procedure命令建立存储过程和存储函数

语法:
create or replace procedure 过程名(参数列表) as PL/SQL 子程序体(说明部分);

事例:
(a)打印一个存储过程:打印HelloWorld(无参数)
create or replace procedure sayhelloworld
as
--说明部分
begin
dbms_output.put_line('Hello World !!!');
end;
/
在编译器左边的过程里形成大写的SAYHELLOWORLD

对其调用:
方法一:
execute 简写为exec sayhelloworld();
方法二:
begin
sayhelloworld();
sayhelloworld();
end;
/

(b)带参数的存储过程
事例:为指定的员工,涨100块钱的工资,并且打印涨前和涨后的薪水
思路:1、创建一个带参数的存储过程
2、给指定的员工涨100块钱的工资,并且打印涨前和涨后的薪水
create or replace procedure raisesalary(eno in number)
as
--定义一个变量保存涨钱的薪水
psal emp.sal%type;
begin
--得到员工涨前的薪水
select sal into psal from emp where empno=eno;

--给员工涨100
update emp set sal=sal+100 where empno=eno;
dbms_output.put_line('涨前薪水 :'||psal||'涨后薪水 :'||(psal+100));

--是否需要commit?
--注意:一般不在存储过程或者存储函数中,commit和rollback.原则不绝对
end;
/

如何调用:
begin
raisesalary(7839);
raisesalary(7566);
commit;
end;

如何调试
注意:不推荐远程调试,推荐本地调试
过程-->右键-->编译以进行调试

设置断点
select sal into psal from emp where empno=eno;
点击瓢虫调试
更改值 ENO := 7839; 点击确定
授权
系统认证登录:sqlplus / as sysdba
grant DEBUG CONNECT SESSION ,DEBUG ANY PROCEDURE to scott;
右键点击检测psal
调试
点击F8

2、掌握存储函数
函数为一命名的存储程序,可带参数,并返回一计算值.
函数和过程的结构类似,但必须有一个return子句,用于返回函数值.

(1)创建存储函数的语法
create or replace function 函数名(参数列表)
return 函数值类型
as
PL/SQL子程序体;

事例:查询某个员工的年收入
create or replace function queryempincome(eno in number)
return number
as
--定义变量保存员工的薪水和奖金
psal emp.sal%type;
pcomm emp.comm%type;
begin
--得到该员工的月薪和奖金
select sal,comm into psal,pcomm from emp where empno=eno;
--直接返回年收入
return psal*12+nvl(pcomm,0);
end;
/

set linesize 200
select * from emp;

调用存储函数

(2)in和out参数
一般来讲,存储过程和存储函数的区别在于存储函数可以有一个返回值,而存储过程没有返回值.

存储过程和存储函数都可以有out参数
存储过程和存储函数都可以有多个out参数
存储过程可以通过out参数来实现返回值

什么时候用存储过程/存储函数?
原则:
-- 如果只有一个返回值,用存储函数,否则,就用存储过程.

----out参数,查询某个员工姓名,月薪和职位
create or replace procedure queryempinform(eno in number, pename out varchar2,psal out number,pjob out varchar2)
as
begin
--得到该员工的姓名,月薪和职位
select ename,sal,empjob into pename,psal,pjob from emp where empno=eno;
end;
/

思考:(1)查询某个员工的所有信息---->out参数太多了
set linesize 80
desc emp
(2)查询某个部门中所有员工的所有信息--->out中返回集合

(3)在应用程序中访问存储过程和存储函数
(a)访问存储过程
public class JdbcUtils {
private static String url = "jdbc:oracle:thin:@localhost:1521:orcl";
private static String username = "scott";
private static String password = "tiger";
private static Connection conn;

public static Connection getConnection() {
conn = null;
try {
conn = DriverManager.getConnection(url, username, password);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接获取失败");
}
return conn;
}

// 关闭连接对象
public static void close(Connection conn) {
if (conn != null) {
try {
conn.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}

public static void close(Statement stmt) {
if (stmt != null) {
try {
stmt.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}

public static void close(ResultSet rs) {
if (rs != null) {
try {
rs.close();
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("oracle连接关闭失败");
}
}
}
}

public class TestProcedure {

@Test
public void testProcedure() {
String sql = "{call queryempinform(?,?,?,?)}";
Connection conn = null;
CallableStatement call = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

//对于in参数,赋值
call.setInt(1, 7839);
//对于out参数,申明
call.registerOutParameter(2, OracleTypes.VARCHAR);
call.registerOutParameter(3, OracleTypes.NUMBER);
call.registerOutParameter(4, OracleTypes.VARCHAR);

//执行调用
call.execute();

//取出结果
String name =call.getString(2);
double sal =call.getDouble(3);
String job =call.getString(4);
System.out.println(name+"\t"+sal+"\t"+job);

} catch (Exception e) {
e.printStackTrace();
}finally{
JdbcUtils.close(conn);
JdbcUtils.close(call);
}
}

}
(b)访问存储函数
public class TestFunction {

@Test
public void testFunction() {
String sql = "{?=call queryempincome(?)}";
Connection conn = null;
CallableStatement call = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

// 对于输出参数,申明
call.registerOutParameter(1, OracleTypes.NUMBER);

// 对于参数赋值
call.setInt(2, 7839);

// 执行调用
call.execute();

// 取出结果

double income = call.getDouble(1);

//打印结果集
System.out.println("年收入:" + income);

} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
JdbcUtils.close(call);
}
}
}

(4)在out参数中使用光标

(a)申明包结构
(b)包头
(c)包体

事例:查询某个部门中所有员工的所有信息

包头:
create or replace package mypackage as
--type自定义类型empcursor
type empcursor is ref cursor;
procedure queryEmpList(dno in number,empList out empcursor);
end mypackage;
*****包体需要实现包头中生命的所有方法*******

操作:
程序包----->右键--->新建程序包--->包名设置mypackage--->确定--->编译--->ctril+s执行

包体:
create or replace package body mypackage as

procedure queryEmpList(dno in number,empList out empcursor) as
begin

open empList for select * from emp where deptno =dno;
end queryEmpList;
end mypackage;

操作:
选中mypackage-->右键-->创建主体--->编译--->ctril+s执行

查看包:
desc mypackage

注意:需要带上包名访问

(5)在应用中访问包中的存储过程
public class TestMypackage {
@Test
public void testMypackage() {
String sql = "{call MYPACKAGE.queryEmpList(?,?)}";
Connection conn = null;
CallableStatement call = null;
ResultSet rs = null;

try {
// 得到一个连接
conn = JdbcUtils.getConnection();
// 通过连接创建出statement
call = conn.prepareCall(sql);

// 对于参数赋值
call.setInt(1, 10);

// 对于输出参数,申明
call.registerOutParameter(2, OracleTypes.CURSOR);

// 执行调用
call.execute();

// 取出该部门的所有员工信息

rs = ((OracleCallableStatement) call).getCursor(2);
while (rs.next()) {
// 该员工的员工号/薪水/职位
int empno =rs.getInt("empno");
String name =rs.getString("ename");
double salary = rs.getDouble("sal");
String job = rs.getString("empjob");
System.out.println(empno +"\t"+name+"\t"+salary+"\t"+job);

}

} catch (Exception e) {
e.printStackTrace();
} finally {
JdbcUtils.close(conn);
JdbcUtils.close(call);
JdbcUtils.close(rs);
}
}
}

Oracle学习笔记(十二)的更多相关文章

  1. Oracle学习笔记十二 子程序(存储过程、自定函数)和程序包

    子程序 子程序:命名的 PL/SQL 块,编译并存储在数据库中.   子程序的各个部分: 1.声明部分 2.可执行部分 3.异常处理部分(可选) 子程序的分类: 1.过程 - 执行某些操作 2.函数 ...

  2. python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL

    python3.4学习笔记(十二) python正则表达式的使用,使用pyspider匹配输出带.html结尾的URL实战例子:使用pyspider匹配输出带.html结尾的URL:@config(a ...

  3. Go语言学习笔记十二: 范围(Range)

    Go语言学习笔记十二: 范围(Range) rang这个关键字主要用来遍历数组,切片,通道或Map.在数组和切片中返回索引值,在Map中返回key. 这个特别像python的方式.不过写法上比较怪异使 ...

  4. java jvm学习笔记十二(访问控制器的栈校验机制)

    欢迎装载请说明出处:http://blog.csdn.net/yfqnihao 本节源码:http://download.csdn.net/detail/yfqnihao/4863854 这一节,我们 ...

  5. (C/C++学习笔记) 十二. 指针

    十二. 指针 ● 基本概念 位系统下为4字节(8位十六进制数),在64位系统下为8字节(16位十六进制数) 进制表示的, 内存地址不占用内存空间 指针本身是一种数据类型, 它可以指向int, char ...

  6. Python学习笔记(十二)—Python3中pip包管理工具的安装【转】

    本文转载自:https://blog.csdn.net/sinat_14849739/article/details/79101529 版权声明:本文为博主原创文章,未经博主允许不得转载. https ...

  7. oracle学习笔记(二十) 子程序——函数与触发器

    子程序--函数 语法 之前select语句中使用的函数,都是SQL内置函数,我们可以通过自定义函数更满足我们的需要. 自定义函数的语法和存储过程差不多. create [or replace] $fu ...

  8. oracle学习笔记(二十二) REF 动态游标

    动态游标 定义语法 --声明 $cursor_name$ sys_refcursor --打开动态游标 open $cursor_name$ is 查询语句; --关闭游标 close $cursor ...

  9. Oracle学习笔记(二)——临时表

    在针对大数据量的多表级联查询或复杂事务处理的时候,引入Oracle临时表是一种不错的策略.因此,在解决实际需求时经常会遇到需要使用存储过程和临时表相互配合的情况.下面就Oracle如何创建临时表以及注 ...

随机推荐

  1. 二:状压dp

    一:状压dp的基本特征 状态压缩问题一般是指用十进制的数来表示二进制下的状态 这种用一个数来表示一组数,以降低表示状态所需的维数的解题手段,就叫做状态压缩. 常用到位运算 二:位运算 &:与运 ...

  2. const_cast

    函数原型: const_cast < type-id > ( expression ) 去掉const属性:const_cast<int*> (&num),常用,因为不 ...

  3. JProfiler 8(一个很好的java性能监控工具) 下载和注册码

    windows x64 zip下载地址:http://download-aws.ej-technologies.com/jprofiler/jprofiler_windows-x64_8_0_1.zi ...

  4. PHP调用Linux的命令行执行文件压缩命令&&创建文件夹修改权限

    一开始,我和普通青年一样,想到用PHP内置的 ZipArchive纠结的是环境上没安装zip扩展,想采用用PHP调用Linux的命令行 ,执行压缩命令,感兴趣的朋友可以了解下,希望本文对你有所帮助 前 ...

  5. js 按字段分组

    var data = [{"id":"32b80b76-a81e-4545-8065-1e7c57180801","userId":&quo ...

  6. 解决 ERROR 1045 (28000): Access denied for user 'root'@'localhost' (using password: YES) 问题(转载)

    最近新装好的mysql在进入mysql工具时,总是有错误提示:# mysql -u root -pEnter password:ERROR 1045 (28000): Access denied fo ...

  7. 巧用c++11 的forward实现可变参数构造,生成智能指针

    C++11 提供强大的智能指针shared_ptr来管理内存,避免使用裸指针带来的各种不确定访问造成的程序崩溃. 为了强制使用智能指针,一个简单的办法是,将类的构造函数析构函数声明为protected ...

  8. delete,truncate,drop的区别

    操作 删除对象 表和索引的空间 是否回滚 时间 delete table和view的数据,可以使用where精确删除,删除会触发触发器 表或索引的空间不变化 是dml,可以rollback回滚 最慢 ...

  9. CentOS 环境下基于 Nginx uwsgi 搭建 Django 站点

    因为我的个人网站 restran.net 已经启用,博客园的内容已经不再更新.请访问我的个人网站获取这篇文章的最新内容,CentOS 环境下基于 Nginx uwsgi 搭建 Django 站点 以下 ...

  10. WMI获取计算机信息

    On Error Resume NextstrComputer = "."strInfo = ""Set objWMIService = GetObject(& ...