存储过程:是指函数在数据库中提供提供所有用户程序调用的子程序叫做存储过程。
存储过程和存储函数:
相同点:完成特定功能的程序。不同点:是否用return语句返回值。
语法:用creat [or replace] procedure 过程名(参数列表) AS PLSQL子程序体 命令建立存储过程和存储函数
备注:其中AS相当于我们的declare用来声明程序的具体内容,PLSQL子程序体 一般是began....end...
第一个存储过程函数(sql窗口,这里我是不带参数的):
create or replace procedure sayhello--oracle数据库会默认转大写
as
begin
dbms_output.put_line('hello word');
end;
(1)调用存储过程的两种方法:exec sayhello();
(2)在其他过程函数/过程中调用
begin
sayhello();
end;
/
下面验证下:(sqlplus登录下oracle数据库)
SQL> set serveroutput on; 打开屏幕显示开关
SQL> exec sayhello();
hello word
PL/SQL 过程已成功完成。
SQL> begin
2 sayhello();
3 sayhello();
4 end;
5 /
hello word
hello word
PL/SQL 过程已成功完成。
利用存储过程给某个员工涨薪水
1.这里我自己随便创造了一张员工表
2.编写涨工资的存储过程
CREATE OR REPLACE
procedure addsalary(empno in number,money in number)--in 输入型参数
as
--定义一个局部变量用来记录涨薪水之前的工资
salarybefore testemp.salary%TYPE;
salaryafter testemp.salary%TYPE;
begin
select salary into salarybefore from testemp where id=empno;--使用into关键字赋值给定义变量
update testemp set salary=salary+money where id=empno;
select salary into salaryafter from testemp where id=empno;
--需不需要在此处做提交或者回滚操作???
--打印涨前 涨后的薪水
dbms_output.put_line('涨前:' ||salarybefore||'涨后:' ||salaryafter);
end;
思考:需要在存储过程中做提交/回滚操作吗?
答:一把不做提交回滚操作,通常提交回滚操作是由调用者来完成的,假设此处过程被另一个过程调用,但是如果做了提交回滚,那么你下面调用其它过程,假设此处回滚了,那么你下一个过程的调用就不会得到执行,那意味着这两个被调用的子过程就不处于同一个事物中
存储过程debug调试:
利用可视化工具调试发现报错:Debugging requires the DEBUG CONNECT SESSION system privilege
所以需要开启权限:
- sqlplus / as sysdba;最高权限登录 无需用户名密码输入,采用主机认证方式
- show user 查看当前用户 SYS 这个是超级管理员
- grant debug connect session,debug any procedure to scott;给scott用户授予过程调试权限 会显示授权成功
这里推荐navicat可视化工具调试 很好用
存储函数
语法:create or replace FUNCTION 函数名(参数列表)
return 函数值类型
AS
PLSQL子程序体;
示例:结算某个员工年薪(这里没算年终奖)
create or replace function yearmoney(p_empno in number)
return number
as
v_salary testemp.salary%type;--定义临时月薪
begin
select salary into v_salary from testemp where id=p_empno;
return v_salary*12;
end yearmoney;
java后台调用
需要引入ojdbc14.jar 在oracle安装目录下jdbc/lib下面 idea工具crtl+shift+alt+s 导入第三方包
package 存储过程;
import oracle.jdbc.OracleTypes;
import org.junit.Test;
import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.SQLException;
/**
* @author Heian
* @time 19/04/15 23:19
* 用途:java调用存储函数(好处就是直接在数据库层计算,而不是放在java层)
*/
public class TestFunction {
@Test
public void testfunc(){
//java调用存储函数语法 {?=call <procedure-name>[(<arg1>,<arg2,....>)]}
String sql = "{?=call yearmoney(?)}";
CallableStatement callableStatement = null;
DBConnect dbConnect = new DBConnect ();
Connection conn = dbConnect.getConnection ();
try {
callableStatement = conn.prepareCall (sql);
//对于输出参数声明
callableStatement.registerOutParameter (1, OracleTypes.NUMBER);
callableStatement.setInt (2,1);//给第二个参数也就是输入参数赋值 id=1 员工
callableStatement.execute ();
double d = callableStatement.getDouble (1);
System.out.println ("员工年薪为:"+d);
} catch (SQLException e) {
e.printStackTrace ();
}finally {
try {
conn.close ();
callableStatement.close ();
} catch (SQLException e) {
e.printStackTrace ();
}
}
}
}
如何在out参数中使用光标
首先需要申明包的结构:其中包括包头(类似于接口层)和包体(类似于impl层),其结构和表,存储过程,存储函数同级。
包头:create or replace package 包名 as
type empcursor is ref cursor;--引用光标类型作为变量empcursor的类型
procedurce queryEmpList(id in number,empList out empcursor );
end 包名;
包体:需要声明包体中所有的方法,也就是存储过程和存储函数
create or replace package body 包名 as
procedure queryEmpList(id in number,empList out empcursor ) as
begin
open empList for select * from testemp where id=id;
end queryEmpList
end 包名;
create or replace package mypkg is
type empcourse is ref cursor;--ref 引用 curse(关键字)光标
procedure queryEmpList(deptno in number,empList out empcourse);
--这里可以继续写其他的过程/函数
end mypkg;
create or replace package body mypkg is
procedure queryEmpList(deptno in number,empList out empcourse) as
begin
--empcourse 光标使用之前需要我们先打开
open empList for select * from testemp where dept=deptno;
dbms_output.put_line(111);
end;
end mypkg;