在java语言中访问存储过程和存储函数
一   引言:
学习了怎么创建和使用存储过程和存储函数之后呢,我们来学习如何在java环境下来访问oracle的存储过程和存储函数了。
在访问之前首先要导入oracle的驱动,导入的驱动在安装的oracle路径下的此目录下找:oracle\product\10.2.0\db_1\jdbc\lib\ojbc14.jar,好,这样,我们就有了oracle驱动,来建一个java类来测试吧!
二  练练吧  -- 存储过程的调用!
1.	首先要先载入驱动来和oracle数据库连接:
private static Connection conn;
static {
		try {
			// 第一步:加载驱动
			Class.forName("oracle.jdbc.driver.OracleDriver");
			// 得到连接对象  test1是用户的名字
			conn = DriverManager.getConnection(
					"jdbc:oracle:thin:@localhost:1521:orcl", "test1", "test1");
		} catch (ClassNotFoundException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
2.我们来调用第一种存储过程,存储过程的内容为:
 create or replace procedure selectEmp(emp_no in number, ename out varchar2,job out varchar2 ,sal out number) is
begin
  select ename,job,sal into ename,job,sal from emp where empno=emp_no;
end selectEmp;

在java中调用上面的存储过程,代码为:
public static void testprocedure() {
		try {
			// 创建callabStatement对象来调用存储过程 通过占位符传递的是int和out的参数,
			CallableStatement cas = conn
					.prepareCall("{call selectEmp(?,?,?,?)}");
			// 从1开始
			int index = 1;
			// 为占位符赋值 输入参数赋值
			cas.setInt(index++, 7369);
			// 为输出参数赋值
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.VARCHAR);
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.VARCHAR);
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.NUMBER);

			// 执行操作 返回的不是ResultSet 如果返回的是ResultSet 则为true,返回的是空则为false
			boolean flag = cas.execute();

			System.out.println(flag);
			// 判断
			if (!flag) {
				// 获取值
				String ename = cas.getString(2);
				String job = cas.getString(3);
				int sal = cas.getInt(4);
				System.out.println(ename);
				System.out.println(job);
				System.out.println(sal);
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

3.调用存储过程,返回的是一行记录
	create or replace procedure selectemp1(emp_no in number, emp_row out emp%rowtype) is
begin
  select *  into emp_row from emp where empno=emp_no;
end selectemp1;
在java中的调用
public static void testprocedureRow() {
		try {
			// rowtype类型的
			CallableStatement cas = conn.prepareCall("{call selectemp1(?,?)}");
			int index = 1;
			// 为占位符赋值 输入参数赋值
			cas.setInt(index++, 7369);
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.ARRAY);
			boolean flag = cas.execute();
			System.out.println(flag);
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
4.通过存储过程来得到emp下的所有的员工
	要得到所有的员工,提供的存储过程为:
	声明包结构:
	create or replace package empPackage is
 	 -- 声明需要的类型
  	type empcursor is ref cursor;
  		--存储过程的声明  参数中使用了type变量声明的类型
 		 procedure selectEmps(emplist out empcursor);
end empPackage;
创建包:
create or replace package body empPackage is
--包中声明 存储过程的实现  方法的变量必须一致
 		 procedure selectEmps(emplist out empcursor)  is
  		--s声明返回的变量
  		begin
    		--为光标赋值 
   			open emplist for select * from emp;
  	end;
  		--结束包体
end empPackage;

在java中调用存储过程为:
public static void getprocedurePackage() {
		try {
			CallableStatement cas = conn
					.prepareCall("{call empPackage.selectEmps(?)}");
			int index = 1;
			// 为占位符赋值 输入参数赋值
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.CURSOR);
			boolean flag = cas.execute();
			System.out.println(flag);
			// 调用里边的getCursor方法获取返回的ResultSet结果集
			ResultSet rs = ((OracleCallableStatement) cas).getCursor(1);
			while (rs.next()) {
				System.out.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			e.printStackTrace();
		}
	}

三   存储函数的调用
1.	存储函数,查询某个员工的总工资
create or replace function sumSal(emp_no number)--function声明(参数值必须有类型)
return number --必须有返回值
as
--声明变量
emp_sal emp.sal%type;
emp_comm emp.comm%type;
total emp.sal%type;
begin
  select sal,comm into emp_sal,emp_comm from emp where empno=emp_no;
  total := emp_sal*12+nvl(emp_comm,0);
  return total;--必须返回,返回值类型一定相同
end;

用java来调用存储函数
public static void getfunction() {
		try {
			//创建预处理对象
			CallableStatement cas = conn.prepareCall("{?=call sumSal(?)}");
			int index = 1;
			//按顺序位置 parameterIndex 将 OUT 参数注册为 JDBC 类型 sqlType。
			//所有 OUT 参数都必须在执行存储过程前注册
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.NUMBER);
			// 为占位符赋值
			cas.setInt(index++, 7369);
			
			boolean flag = cas.execute();//执行
			System.out.println(flag);
			
			System.out.println(cas.getInt(1));
			/**
			 * 参数是根据编号按顺序引用的,第一个参数的编号是 1。 

			 * 它们的值是在执行后通过此类提供的 get 方法检索的。 
			 */

		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

2.	查询所有的员工,存储函数为
(1)创建包体
create or replace package functionEmps is
  --声明类型
  		type empcl is ref cursor;
 		 function queryEmps return empcl;
end functionEmps;
(2)创建包
create or replace package body functionEmps is
function queryEmps return empcl is
 	 emp_cl empcl;
  	begin
    		open emp_cl for select * from emp;
   	 return emp_cl;
  	end;
end functionEmps;
在java中访问存储函数:
public static void testpackage(){
		try {
			CallableStatement cas = conn.prepareCall("{?=call functionEmps.queryEmps}");
			int index = 1;
			// 为占位符赋值 输入参数赋值
			cas.registerOutParameter(index++, oracle.jdbc.OracleTypes.CURSOR);
			boolean flag = cas.execute();
			System.out.println(flag);

			ResultSet rs = ((OracleCallableStatement) cas).getCursor(1);
			while (rs.next()) {
				System.out.println(rs.getInt(1));
			}
		} catch (SQLException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
看这么多代码,是不是特别烦呢!而且还不懂里面的类的应用,下面我来简单的说说吧!
Oracle的加载驱动:Class.forName("oracle.jdbc.driver.OracleDriver");
和获取连接:jdbc:oracle:thin:@localhost:1521:orcl", "test1", "test1"
这些是必须会写的。我们
(1)	来了解一下CallableStatement接口,看看它的用法吧!
CallableStatement是属性java.sql下的接口,用于执行 SQL 存储过程的接口。JDBC API 提供了一个存储过程 SQL 转义语法,该语法允许对所有 RDBMS 使用标准方式调用存储过程。此转义语法有一个包含结果参数的形式和一个不包含结果参数的形式。如果使用结果参数,则必须将其注册为 OUT 型参数。其他参数可用于输入、输出或同时用于二者。参数是根据编号按顺序引用的,第一个参数的编号是 1。
(2)registerOutParameter是它类的一个方法
 按顺序位置 parameterIndex 将 OUT 参数注册为 JDBC 类型 sqlType。
(3)cas.execute();返回的是一个boolean类型的,在此 PreparedStatement 对象中执行 SQL 语句,该语句可以是任何种类的 SQL 语句。一些特别处理过的语句返回多个结果,execute 方法处理这些复杂的语句,executeQuery 和 executeUpdate 处理形式更简单的语句。 
execute 方法返回一个 boolean 值,以指示第一个结果的形式。必须调用 getResultSet 或 getUpdateCount 方法来检索结果,并且必须调用 getMoreResults 移动到任何后面的结果。