Oracle存储过程

什么是存储过程

存储过程是一组为了完成特定功能的SQL语句,经编译后存在数据库,存储过程是数据库中的一个重要对象。

ps:有人说:任何一个设计良好的数据库应用程序都应该用到存储过程,我觉得这个不一定,其实很多互联网公司的WEB应用程序都没有用到存储过程,难道就能说他们的应用程序设计的不好吗?现实中,银行、金融相关的公司使用存储过程多一些。

存储过程的优缺点

优点

  1. 效率高:创建的时候就会编译,调用时不需要重新编译,而直接写SQL每次执行都先编译再执行。
  2. 安全:与直接写SQL语句相比,存储过程不存在SQL注入的问题。可以向用户授予存储过程的访问权限,而不是直接授予表的访问权限,控制对特定数据的访问。
  3. 降低网络流量:存储过程直接存储在数据库中,所以不会产生大量的SQL代码流量。

缺点

  1. 可移植性很差:应用程序更换其他数据库,需要将原有的存储过程重新写一遍,并且如果你的存储过程中包含大量的业务逻辑,这样就会更加麻烦。
  2. 代码可复用性很差:面向对象的思维在这里完全没有用,两个很相近的功能,需要写两个存储过程,虽然可以相互调用,但是不能利用继承等面向对象的功能。

语法

create or replace procedure <存储过程名>
[(
参数列表:p_name1 in <输入参数数据类型>,p_name2 out <输出参数数据类型>
,p_name3 in out <参数数据类型>
)]
as或is
[定义变量:v_name1 <变量数据类型>]
begin
  <执行特定的操作或者任务,可以进行增删改查>
  end;

注意

如果没有参数()要去掉,存储过程主体不能为空(begin和end之间不能什么都不做)

说明

  1. in表示输入参数,out表示输出参数,可以同时使用in和out表示既是输入参数又是输出参数。
  2. 声明变量时可以使用 列名+%type 来声明类型
  3. 存储过程主体做select查询时,必须使用into将结果集保存到变量中
  4. :=表示赋值操作

DEMO

登录Oracle数据库scott用户,初始密码tigger

1.定义一个存储过程,用来查询指定部门的员工的人数和平均工资,如果部门不存在,就引发一个自定义异常,显示“部门编号不存在!”(部门编号作为存储过程的输入参数,在调用存储过程前由用户输入,该部门员工的人数和平均工资需要返回)

创建

create or replace procedure proc1(
p_deptno in emp.deptno%type,
p_count_emp out number ,
p_avg_sal out emp.sal%type
)
is
v_row_num number:=0;
error1 exception;
beginselect count(*) into p_count_emp from emp e where e.deptno=p_deptno;if p_count_emp!=0  thenselect avg(e.sal) into p_avg_sal from emp e where e.deptno=p_deptno;else raise error1;end if;exception when error1 thendbms_output.put_line('部门编号不存在');
end;

语句块调用

declare
a emp.deptno%type;
b number:=0;
c emp.sal%type:=0;
begina:=&部门编号;proc1(a,b,c);dbms_output.put_line('部门编号为'||a||'的员工人数为' ||b||',平均工资为:'||c);end;

2.存储过程相互调用

创建

--根据员工编号删除员工
create or replace procedure proc3
(p_empno in emp.empno%type
)
as
begindelete from emp e where e.empno=p_empno;commit;end;--首先调用上面的那个存储过程,然后用输出参数返回剩下的员工人数
create or replace procedure proc4(
p_empno in emp.empno%type,
p_nums_afterdelete out number)
as
beginproc3(p_empno);select count(*) into p_nums_afterdelete from emp;end; 

语句块调用

declare
p_empno emp.empno%type:=&请输入员工编号;
p_nums_afterdelete number:=0;
beginproc4(p_empno,p_nums_afterdelete);dbms_output.put_line('已成功删除员工编号为'||p_empno||'的员工'||',当前还剩的员工总数为'||p_nums_afterdelete);end;

3.使用call关键字直接调用存储过程

create or replace procedure proc2(a in number,b in number)
as 
c number;
beginc :=a+b;dbms_output.put_line(c);end;call proc2(1,1);

JAVA调用存储过程

首先需要下载classes12.jar、ojdbc14.jar,并导入到自己的工程里。

插入数据

package java_procedure;import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;//只需ojdbcjar包就行
/*--java调用存储过程
create table tb_student(
stu_id varchar2(20),
stu_name varchar2(20)
);
--①没有返回值的存储过程
create or replace procedure TESTA(
p_stu_id   in tb_student.stu_id%type,
p_stu_name in tb_student.stu_name%type) 
as
begininsert into tb_student(stu_id, stu_name)values(p_stu_id, p_stu_name);
end TESTA;
/*/
public class TestProcedureOne {public static void main(String[] args) {CallableStatement cs=null;Connection conn=null;String driver="oracle.jdbc.driver.OracleDriver";String url="jdbc:oracle:thin:@localhost:1521:orcl";String userName="a3";String pwd="a123";try {Class.forName(driver);conn=DriverManager.getConnection(url,userName,pwd);cs=conn.prepareCall("{call testa(?,?)}");cs.setString(1,"001");cs.setString(2, "zhangsan");cs.execute();} catch (ClassNotFoundException e) {e.printStackTrace();}catch (SQLException e) {e.printStackTrace();}finally{try {if (cs!=null) {cs.close();}if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}

条件查询

package java_procedure;import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;//只需ojdbcjar包就行
/*
--②有返回值的存储过程
CREATE OR REPLACE PROCEDURE TESTB(
p_stu_id   in tb_student.stu_id%type,
p_stu_name out tb_student.stu_name%type) AS
BEGINSELECT stu_name INTO p_stu_name FROM tb_student WHERE stu_id = p_stu_id;
END TESTB;
/*/
public class TestProcedureTwo {public static void main(String[] args) {CallableStatement cs=null;Connection conn=null;String driver="oracle.jdbc.driver.OracleDriver";String url="jdbc:oracle:thin:@localhost:1521:orcl";String userName="a3";String pwd="a123";try {Class.forName(driver);conn=DriverManager.getConnection(url,userName,pwd);cs=conn.prepareCall("{call testb(?,?)}");cs.setString(1,"001");cs.registerOutParameter(2, oracle.jdbc.OracleTypes.VARCHAR);//registerOutParameter()方法的第二个参数:如果是MySQL的驱动,使用Types.VARCHARcs.execute();String stuName=cs.getString(2);System.out.println(stuName);} catch (ClassNotFoundException e) {e.printStackTrace();}catch (SQLException e) {e.printStackTrace();}finally{try {if (cs!=null) {cs.close();}if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}

查询所有

package java_procedure;import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;//要用classes12.jar,ojdbcjar包有bug
/*
--返回一个列表的存储过程
--建一个程序包
CREATE OR REPLACE PACKAGE TESTPACKAGE  ASTYPE Test_CURSOR IS REF CURSOR;
end TESTPACKAGE;
--建立存储过程
CREATE OR REPLACE PROCEDURE TESTC(
p_CURSOR out TESTPACKAGE.Test_CURSOR) IS
BEGINOPEN p_CURSOR FOR SELECT * FROM tb_student;
END TESTC;*/
public class TestProcedureThree {public static void main(String[] args) {CallableStatement cs=null;Connection conn=null;ResultSet rs=null;String driver="oracle.jdbc.driver.OracleDriver";String url="jdbc:oracle:thin:@localhost:1521:orcl";String userName="a3";String pwd="a123";try {Class.forName(driver);conn=DriverManager.getConnection(url,userName,pwd);cs=conn.prepareCall("{call testc(?)}");cs.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);cs.execute();rs=(ResultSet)cs.getObject(1);//上面一行代码可以这样写: rs=((OracleCallableStatement)cs).getCursor(1);while(rs.next()){System.out.println("ID:"+rs.getString(1)+"\t"+"姓名:"+rs.getString(2));}} catch (ClassNotFoundException e) {e.printStackTrace();}catch (SQLException e) {e.printStackTrace();}finally{try {if (rs!=null) {rs.close();}if (cs!=null) {cs.close();}if (conn!=null) {conn.close();}} catch (SQLException e) {e.printStackTrace();}}}}

存储过程返回游标类型

  • 创建新表,使用bulk collect into
create or replace procedure getHighSalPerson(p_emp out sys_refcursor)
is
v_avg_sal number;
beginselect avg(sal) into v_avg_sal from emp ;open p_emp for select empno,ename,job,sal from emp where sal>=v_avg_sal;
end;create table t_emp_high_sal(empno varchar2(100 byte),ename varchar2(100 byte),job varchar2(100 byte),sal number);declare
type row_type is table of  t_emp_high_sal%rowtype;
emp_cursor sys_refcursor;
emp_row row_type;
begingetHighSalPerson(emp_cursor);fetch emp_cursor bulk collect into emp_row;for i in 1..emp_row.count loopdbms_output.put_line('员工编号:'||emp_row(i).empno||',员工姓名:'||emp_row(i).ename||',职位:'||emp_row(i).job||',工资:'||emp_row(i).sal);end loop;close emp_cursor;
end;
  • 定义包类型
create or replace procedure getHighSalPerson(p_emp out getHighsalperson_package.type_cursor)
is
v_avg_sal number;
beginselect avg(sal) into v_avg_sal from emp ;open p_emp for select empno,ename,job,sal from emp where sal>=v_avg_sal;
end;create or replace package getHighsalperson_package
istype type_cursor is ref cursor;type type_record is record(empno varchar2(100 byte),ename varchar2(100 byte),job varchar2(100 byte),sal number);
end;declare
emp_cursor getHighsalperson_package.type_cursor;
emp_row getHighsalperson_package.type_record;
begingetHighSalPerson(emp_cursor);loop fetch emp_cursor into emp_row;exit when emp_cursor%notfound;dbms_output.put_line('员工编号:'||emp_row.empno||',员工姓名:'||emp_row.ename||',职位:'||emp_row.job||',工资:'||emp_row.sal);end loop;close emp_cursor;
end;
  • 直接用空结果集的游标
create or replace procedure getHighSalPerson(p_emp out sys_refcursor)
is
v_avg_sal number;
beginselect avg(sal) into v_avg_sal from emp ;open p_emp for select empno,ename,job,sal from emp where sal>=v_avg_sal;
end;declare
cursor emp_cur is select empno,ename,job,sal from emp where 1=2;
emp_cursor sys_refcursor;
emp_row emp_cur%rowtype;
begingetHighSalPerson(emp_cursor);loop fetch emp_cursor into emp_row;exit when emp_cursor%notfound;dbms_output.put_line('员工编号:'||emp_row.empno||',员工姓名:'||emp_row.ename||',职位:'||emp_row.job||',工资:'||emp_row.sal);end loop;close emp_cursor;
end;

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/530421.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

解决debug JDK source无法查看局部变量的问题

首先进入传送门&#xff1a;https://blog.csdn.net/majian_1987/article/details/51273609 进行上面的操作之后&#xff0c;这个时候我们来debug一下jdk源码&#xff0c;发现可以查看局部变量。但是这时候又发现一个问题&#xff0c;在我自己的代码里按住ctrl鼠标左键单击无法…

【JAVA基础篇】多线程

学习Java的多线程知识之前&#xff0c;我们先来了解一下进程和线程的概念&#xff0c;以及他们之间的关系。 进程 基本概念 进程是具有独立功能的程序在某个数据集合上的一次执行过程。 特点 进程是操作系统进行资源分配的基本单位。每个进程都有自己的地址空间&#xff0…

配置JAVA开发环境

1、首先去Oracle官方网站下载所需版本的JDKhttp://java.sun.com/products/archive/&#xff0c;然后安装&#xff0c;其实只需要安装jdk就可以了&#xff0c;不需要安装jre 2、按照后配置环境变量JAVA_HOME 然后在path最前面添加%JAVA_HOME%\bin; 3、cmd中输入java -version,提…

【JAVA基础篇】枚举

/*** 一组相同类型的常量的集合* author cc**/ public class EnumDemo {public static void main(String[] args) {//遍历for(WorkDay workDay:WorkDay.values()){System.out.println("序号&#xff1a;"workDay.ordinal());//ordinal&#xff0c;返回枚举常量的序号…

【JAVA基础篇】集合框架

一、集合框架图 Java集合框架主要包含两种类型的容器&#xff0c;一是集合(Collection)&#xff0c;存储元素集合&#xff0c;二是图(Map)&#xff0c;存储键(key)-值(value)对.Collection接口下面有两个重要的子接口List和Set&#xff0c;再下面是一些抽象类&#xff0c;最后是…

【JAVA基础篇】对象初始化过程

我们都知道&#xff0c;创建对象是由 new关键字调用构造方法 返回类实例&#xff08;实际上还可以通过反射来创建实例&#xff09;。 例如 : Person jack new Person(); 这句话到底做了什么事情呢 &#xff1f; 其实就是讲对象的初始化过程。 1、 new 用到了Person.class,所…

【Java基础篇】try catch finally语句包含return语句时的执行过程

网上有很多人探讨Java中异常捕获机制try…catch…finally块中的finally语句是不是一定会被执行&#xff1f; 很多人都说不是&#xff0c;当然他们的回答是正确的&#xff0c;经过我试验&#xff0c;至少有两种情况下finally语句是不会被 try语句没有被执行到&#xff0c;如在…

eclipse指定JDK版本启动,解决version XXX of the JVM is not suitable for this product.Version:XXX 问题

问题描述&#xff1a;启动eclipse时&#xff0c;提示version 1.7.0 of the JVM is not suitable for this product.Version:1.8 or greater is required. 原因分析&#xff1a;原因是我的笔记本安装了多个JDK版本&#xff0c;但是现在我的JAVA_HOME配置的是jdk1.7的路径&#x…

【JAVA基础篇】Socket编程

一、Socket的概念 Socket是一种通讯机制&#xff0c;通常称为套接字。英文原意是插座&#xff0c;顾明思义&#xff0c;Socket像是一个多孔插座&#xff0c;可以提供多个端口的连接服务 ps:至于socket在计算机术语中怎么就翻译成了“套接字”这个令人费解的词&#xff0c;这真…

【JAVA基础篇】注解

一、什么是注解&#xff1f; 注解是元数据&#xff0c;所谓元数据就是描述数据的数据。 在annotation诞生之前&#xff08;jdk1.5诞生了注解&#xff09;&#xff0c;甚至之后&#xff0c;xml被广泛的由于描述元数据。但是后来&#xff0c;有一些应用开发工程师和架构师觉得它…

【JAVA基础篇】IO流

一、流的概念 “对语言设计人员来说&#xff0c;创建好的输入&#xff0f;输出系统是一项特别困难的任务。” ――《Think in Java》 无论是系统、还是语言的设计中IO的设计都是异常复杂的。面临的最大的挑战一般是如何覆盖所有可能的因素&#xff0c;我们不仅仅要考虑文件、…

SpringMVC注解

一&#xff0c;RequestMapping 可以用在类和方法上 1.1 作用&#xff1a; 将客户端请求映射到可匹配的类和方法中 1.2 属性&#xff1a; name 给映射指定一个名字 path(同value相同&#xff09; 请求的url&#xff0c;path{"/mixedAttribute1","/mixedA…

【JAVA基础篇】运算符

一、表达式 表达式由运算符和操作数组成 例如&#xff1a; 5 num1 num1num2 sumnum1num2 二、运算符分类 算数运算符、赋值运算符、关系运算符、逻辑运算符、条件运算符、位运算符 三、算数运算符 四、赋值运算符 格式&#xff1a;变量表达式 例如&#xff1a;int n3…

a4纸网页打印 table_打印模板不愁人,你还在打印单调的A4纸吗?

软件介绍早在几年前&#xff0c;社会上就已经开始了数字化、无纸化的推广&#xff0c;但是就算再怎么无纸化&#xff0c;纸张还是有它必要的存在&#xff0c;在工作、学习过程中&#xff0c;打印的需求也必不可少的。但是一般的打印都是比较平庸的&#xff0c;要做会议记录&…

IP地址、子网掩码、网关、默认网关、DNS的理解

IP地址 Internet上为了区分数以亿计的主机而给每个主机分配一个专门的地址&#xff0c;通过IP地址可以访问到每台主机。 子网掩码 子网掩码又称网络掩码、地址掩码、子网络遮罩。它是用来指明一个IP地址哪些位标识的是主机所在的子网&#xff0c;以及哪些位标识的是主机的位…

上证指数30年k线图_技术预判2020:上证指数要突破3500点才会“井喷”

2019年的行情很快就要收官了&#xff0c;截止目前&#xff0c;上证指数今年的涨幅是20.5%&#xff0c;不过可能有部分投资者今年的收益率还没达到大盘指数的平均水平。不管怎样&#xff0c;今年很快就要翻篇了&#xff0c;关键是看2020年股市能不能迎来更好的行情了。而总结得失…

【JAVA基础篇】基本数据类型及自动类型转换

一、8种基本数据类型以及占用内存空间大小 boolean 1byte或4byte byte 8bit/1byte char 16bit/2byte short 16bit/2byte float 32bit/4byte int 32bit/4byte long 64bit/8byte double 64bit/8byte 二、自动类型转换 …

的优缺点_浅谈桉木家具的优缺点

家具现在的材质是有很多的&#xff0c;木质的&#xff0c;石材的&#xff0c;还有真空充气的&#xff0c;都是很不错的类型。桉木家具是现在很多人都喜欢的一种材质&#xff0c;但是很多人对桉木家具的优缺点不是很清楚&#xff0c;为了能够让大家更加清楚的了解桉木家具&#…

【算法篇】递归

一、递归的概念 程序调用自身的编程技巧称为递归。 递归的核心思想就是将一个大规模复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解。 二、递归的优点 使用递归的好处是只需要少量的代码就可以描述出求解问题过程中多次重复的计算&#xff0c;大大减少了程序…

客户说发货慢怎么回复_女生微信说身体不舒服怎么回复关心她?

当你不在女生身边&#xff0c;女生微信给你说身体不舒服&#xff0c;肯定需要说点话来安慰她了。多喝热水肯定是不行了&#xff0c;一点用处都没有&#xff0c;还会让女生觉得你根本不重视她&#xff0c;是在敷衍她&#xff0c;那女生微信说身体不舒服怎么回复关心她呢&#xf…