Oracle存储过程和自定义函数笔记

学习地址:https://www.imooc.com/learn/370

存储过程和存储函数定义:指存储在数据库*所有用户程序调用的子程序叫做存储过程
、存储函数。

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

语法
create [or replace] procedure 过程名(参数列表)
as
plsql程序体


create or replace procedure sayhelloworld
as
--说明部分

begin
dbms_output.put_line('Hello World');
end;


调用存储过程
1.exec sayhelloworld();
2.begin
sayhelloworld();
sayhelloworld();
end;

1 exec 存储过程名();2 begin 存储过程名();end /


创建带参数的存储过程
-- 给指定的员工涨100块钱的工资,并且打印涨前后涨后的薪水 eno:员工号
create or replace procedure raisesalary(eno in number) -- in 这是一个输入参数
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;
-- 一般,这里不需要 commit ! 也不需要 rollback
-- 注意:一般不在存储过程或者存储函数中,commit 和 rollback
-- 打印
dbms_output.put_line('涨前:'||psal||',涨后:'||(psal+100));
end;
/
-- 调用:
begin
raisesalary(7839);
raisesalary(7566);
end;
/

一般不在存储过程中提交或者回滚,大多时间是在调用一次或者多次的时候提交或者回滚
,这样会防止出现意外情况。


创建存储函数的语法

示例:根据员工号,查询员工年收入。

create or replace function queryempincom(eno in numbr)

return number

as

--定义变量保存员工的薪水和奖金

psal emp.sal%type;

pcomm emp.comm%type;

begin

--得到该员工的月薪和奖金
select sal,comm into pasl,pcomm from emp where empno=eno;

--直接返回年收入
return psal*12+nvl(pcomm,0);

end;


存储过程和存储函数都可以通过Out指定一个或多个输出参数。我们可以利用out参数,在
过程和函数中实现返回多个值。


存储过程可以通过out参数返回值。

什么时候用存储过程、存储函数?


一般原则:如果只有一个返回值,用存储函数;否则,用存储过程。


示例:
create or replace procedure queryempinfor(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;

使用JDBC连接数据库

public class JDBCUtile{
  private static String driver="orable.jdbc.OracleDriver";
  private static String url="jdbc:oracle:thin:@192.168.56.101:1521:orcl";
  private static String user="scott";
  private static String password="tiger";
  // 注册数据库的驱动
  static{
      try{
         Class.forName(driver);
         // --> DriverManager.registerDriver(driver);
      }catch(ClassNotFoundException e){
         throw new ExceptionInInitializerError(e);
      }
  }  // 获取数据库连接
  public static Connection getConnection(){
      try{ 
         return DriverManager.getConnection(url,user,password);
      }catch(SQLException e){e.printStackTrace(); }
         return null;
  }

// 释放数据库的资源
  public static void release(Connection conn,Statement st,ResultSet rs){
    if(rs != null){try{ rs.close();}catch(SQLException e){e.printStackTrace();}finally{rs=null;}}
    if(st != null){try{st.close();}catch(SQLException e){e.printStackTrace();}finally{st=null;}}
    if(conn != null){try{conn.close();}catch(SQLException e){e.printStackTrace();}finally{conn=null;}}
    }
}

在应用程序中访问存储过程和存储函数

使用CallachleStatement接口

public void testProcedure(){
//{call <procedure-name>[(<arg1>,<arg2>,...)]}
String sql="call queryempinform(?,?,?,?)";
Connection conn=null;
CallableStatement call=null;
try{
// 得到一个连接
conn=JDBCUtils.getConnection();
// 通过连接创建出statement
call=conn.prepareCall(sql);
// 对于in参数,需赋值,对于out参数,需要申明
call.setInt(1, 7839); // 设置第一个?为 7839
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+"	"+sal+"	"+job);
}catch(Exception e){
e.printStackTrace();
}finally{
JDBCUtils.release(conn,call,null);
}
}

 在out参数中使用光标:

包头:
CREATE OR REPLACE PACKAGE MYPACKAGE AS 
    type empcursor is ref cursor;
    procedure queryEmpList(dno in number,empList out empcursor);
END MYPACKAGE;
包体(需要实现包头中声明的所有方法,包括存储函数、存储方法):
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;  
-- 使用desc查看程序包的结构
 desc MYPACKAGE

所有存储函数的功能都可以有存储过程来代替,为什么在oracle数据库中依然保留存储函数?
原因:数据库版本升级所造成,版本升级最基本的要求就是要向前向下兼容,在oracle数据库最早的版本中是有存储过程和存储函数的区别。如果新版本不支持存储函数,那么老的数据库中若存在存储函数就可能运行出错。