数据库之存储过程

1.存储过程语法

Oracle存储过程基本语法存储过程

  1 CREATE OR REPLACE PROCEDURE 存储过程名

  2 IS

  3 BEGIN

  4 NULL;

  5 END;

行1:

  CREATE OR REPLACE PROCEDURE 是一个SQL语句通知Oracle数据库去创建一个叫做skeleton存储过程, 如果存在就覆盖它;

行2:

  IS关键词表明后面将跟随一个PL/SQL体。

行3:

  BEGIN关键词表明PL/SQL体的开始。

行4:

  NULL PL/SQL语句表明什么事都不做,这句不能删去,因为PL/SQL体中至少需要有一句;

行5:

END关键词表明PL/SQL体的结束

存储过程创建语法:

create orreplace procedure 存储过程名(param1 in type,param2 out type)

as

变量1 类型(值范围);--vs_msg VARCHAR2(4000);

变量2 类型(值范围);

Begin

Select count(*)into 变量1 from 表A where列名=param1;

If (判断条件) then

Select 列名 into 变量2 from 表A where列名=param1;

Dbms_output。Put_line(‘打印信息');

Elsif (判断条件) then

Dbms_output。Put_line(‘打印信息');

Else

Raise 异常名(NO_DATA_FOUND);

End if;

Exception

When others then

Rollback;

End;

例子2

create orreplace procedure EMP_PROCEDURE2(

eno number,  --输入参数,

    name varchar2,

   

)

IS

    emp_null_error EXCEPTION;  --声明异常变量

    PRAGMA EXCEPTION_INIT(emp_null_error,-1400);--非预定义异常,前提:deptno列非空。插入空值会报错

    emp_no_deptno EXCEPTION;  --声明异常变量

PRAGMA EXCEPTION_INIT(emp_no_deptno, -2291);--非预定义异常,

begin

       insert into emp(empno,ename,sal,deptno)values (eno,name,sal,dno);

exception

    when DUP_VAL_oN_INDEX then

        RAISE_APPLICATION_ERROR(-20000,'该雇员已存在');

    when emp_null_error then

        RAISE_APPLICATION_ERROR(-20001,'部门编号不能为空');       

    when emp_no_deptno then

        RAISE_APPLICATION_ERROR(-20002,'不存在该部门编号');                     

end;

EXECUTEEMP_PROCEDURE2(1001,'荣世林',2000,10);

注意事项:

1, 存储过程参数不带取值范围,in表示传入,out表示输出

类型可以使用任意Oracle中的合法类型。

2, 变量带取值范围,后面接分号

3, 在判断语句前最好先用count(*)函数判断是否存在该条操作记录

4, 用select 。。。into。。。给变量赋值

5, 在代码中抛异常用 raise+异常名

 

 

 

 

 

2.CallableStatement 执行存储过程

概述

如果想要执行存储过程,我们应该使用 CallableStatement 接口。

CallableStatement 接口继承自 PreparedStatement 接口。所以 CallableStatement 接口

包含有 Statement 接口和 PreparedStatement 接口定义的全部方法,但是并不是所有的方法我

们都要使用,主要使用的方法有这样几个:

2.1常用方法

返回类型

方法签名

说明

boolean

execute()

执行 SQL 语句,如果第一个结果是 ResultSet 对

象,则返回 true;如果第一个结果是更新计数或者没

有结果,则返回 false

void

registerOutParameter

(int parameterIndex,

int sqlType)

按顺序位置 parameterIndex 将 OUT 参数注册为

JDBC 类型 sqlType,sqlType 为 Types 类中的常量

Type

getType(int

parameterIndex)

根据参数的序号获取指定的 JDBC 参数的值。第一

个参数是 1,第二个参数是 2,依此类推

 

 

 

我们可以使用 execute()方法来执行存储过程。CallableStatement 为所有的数据库提供了

一种统一的标准形式调用存储过程。所以,你将会看到我们使用 execute()调用存储过程的语

法与在 Oracle 中会所有不同。

为了获得存储过程或函数的返回值,我们需要使用registerOutParameter()方法将返回的

参数注册为 JDBC 的类型。 registerOutParameter()方法的第一个参数是参数的序号,第一个

为 1,第二个为 2,以此类推。第二个参数需要一个 int 值,用来标记 JDBC 的类型,我们可以

使用 java.sql.Types 类中的常量来设置这个参数。比如 VARCHAR、DOUBLE 等类型。如果类型不

够用,也可以从具体数据库的驱动中寻找合适的类型常量。如果存储过程或函数有返回值,这

个方法是必须要调用的,否则无法得到返回值,甚至会发生异常。

CallableStatement 接口中定义了很多 get 方法,用于获取存储过程返回的值,根据值的

类型不同,你可以使用不同 get 方法,比如 getInt()、getString()、getDouble()等等。

我们看一下使用 CallableStatement 接口执行存储过程和函数的语法格式。

存储过程:{call<procedure-name>[(<arg1>,<arg2>, ...)]}

函数:{?= call<procedure-name>[(<arg1>,<arg2>, ...)]}

如果要调用存储过程,则使用第一种语法,就是开头不带问号的语法,call 后面是过程名,

如果没有参数,可以省略小括号。

如果要调用函数,则使用第二种语法,开头带有一个问号加等号,实际上这个问号就是一

个占位符,这个问号总是调用函数的第一个占位符。其它部分与过程的语法相同。

这样说起来可能比较抽象,我们通过代码来学习一下。

2.2执行存储过程

(1) 执行不带参但是有返回值的存储过程

存储过程代码如下:

create or replaceprocedure getNewsCount(v_totalCount out number) as

begin

select count(*) intov_totalCount from news_detail;

end;

 

该 存 储 过 程 为 查 询 新 闻 明 细 表 (news_detail) 中新 闻 的 总 记 录 数 , 并 将 结 果 存 储 在

v_totalCount 中返回。执行该存储过程的代码如下:

//获取新闻总数量(执行存储过程)

public intgetTotalCountProc(){

int totalCount=0;

CallableStatementproc=null;

Stringsql="{call getNewsCount(?)}";

getConnection();

try {

proc=conn.prepareCall(sql);

proc.registerOutParameter(1,Types.INTEGER);

proc.execute();

totalCount=proc.getInt(1);

} catch (SQLExceptione) {

e.printStackTrace();

}

return totalCount;

}

(2) 执行带参带返回值的存储过程

存储过程代码如下:

create or replaceprocedure getNewsCount(v_categoryId in number,v_title   in varchar2,v_totalCount out number) as

begin

if (v_categoryId = 0)then

select count(*) intov_totalCount from news_detail

where title like'%'||v_title||'%';

else

select count(*) intov_totalCount from news_detail

where categoryId =v_categoryId

and title like'%'||v_title||'%';

end if;

end;

该存储过程为根据新闻类别 ID(categoryId)以及新闻标题(title)查询新闻明细表

(news_detail)中新闻的总记录数,并将结果存储在 v_totalCount 中返回。其中,新闻类别以

及新闻标题分别以输入参数的形式传入存储过程。执行该存储过程的代码如下:

//根据新闻类别 ID 以及新闻标题获取新闻总记录数

public intgetTotalCount(int categoryId, String title) {

int iCount = 0;

CallableStatementproc = null;

try {

String sql ="{call getNewsCount(?,?,?)}";

getConnection();

proc =conn.prepareCall(sql);

proc.setInt(1,categoryId);

proc.setString(2,title);

proc.registerOutParameter(3,Types.INTEGER);

proc.execute();

iCount =proc.getInt(3);

} catch (Exception e){

e.printStackTrace();

}finally{

if (proc != null){

try {

proc.close();

} catch (SQLExceptione) {

e.printStackTrace();

}

}

closeResource();

}

return iCount;

}

(3) 执行返回值为游标的存储过程

Employees 雇员表(name 雇员姓名;gender 雇员性别;borndate 雇员生日)

存储过程代码如下:

create or replaceprocedure find_emp3(emp_cursor out sys_refcursor) is

begin

open emp_cursor forselect name,gender,borndate from employees;

end find_emp3;

该存储过程为查询所有雇员姓名、性别、生日的存储过程,结果以游标的形式返回。执行

该存储过程的代码如下:

String sql ="{call find_emp3(?)}";

Connection con =null;

CallableStatementcstmt = null;

ResultSet rs = null;

try {

Class.forName("oracle.jdbc.OracleDriver");

con = DriverManager 个.getConnection(

"jdbc:oracle:thin:@localhost:1521:orcl","pbdevj","pwd1234");

cstmt =con.prepareCall(sql);

cstmt.registerOutParameter(1,oracle.jdbc.OracleTypes.CURSOR);

cstmt.execute();

rs =(ResultSet)cstmt.getObject(1);

while (rs.next()) {

//省略

}

} catch { //省略 } finally { //省略 }

(4) 执行函数

函数代码如下:

create or replacefunction find_emp2(emp_no number) return varchar2 is

empname varchar2(20);

 

 

 

begin

select name intoempname from employees where id=emp_no;

return empname;

exception

when no_data_foundthen

return '雇员编号未找到';

end find_emp2;

该函数功能为根据雇员 id 返回姓名。执行该函数的代码如下:

String sql ="{?=call find_emp2(?)}";

Connection con =null;

CallableStatementcstmt = null;

try {

Class.forName("oracle.jdbc.OracleDriver");

con =DriverManager.getConnection(

"jdbc:oracle:thin:@localhost:1521:orcl","pbdevj","pwd1234");

cstmt =con.prepareCall(sql);

cstmt.setInt(2, 1);

cstmt.registerOutParameter(1,Types.VARCHAR);

cstmt.execute();

System.out.println(cstmt.getString(1));

} catch { //省略 } finally { //省略 }

 

 

 

 

 

 

 

 

 

原文地址:https://www.cnblogs.com/liuyandeng/p/5824028.html