一、通过PL/SQL工具连接上Oracle数据库,创建表zx_test_procedure

java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_bc

java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_02

二、创建存储过程

①无返回值的存储过程
存储过程为:

create or replace procedure testa
 (para1 in varchar2,para2 in varchar2) as
 begin
insert into zx_test_procedure(i_id,i_name) values(para1,para2);
 end testa;

java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_JAVA_03


Java调用的代码:


import java.sql.*;

public class TestProcedureOne {
	 public TestProcedureOne() {}
	 public static void main(String[] args ){
	    String driver = "oracle.jdbc.driver.OracleDriver";
	    String strUrl = "jdbc:oracle:thin:@10.10.1.29:1521:testdb";
	    Statement stmt = null;
	    ResultSet rs = null;
	    Connection conn = null;
	    //CallableStatement cstmt = null;
	    try {
	      Class.forName(driver);
	      conn = DriverManager.getConnection(strUrl, "neb", "testneb");
	      CallableStatement proc = null; //创建执行存储过程的对象
	      proc = conn.prepareCall("{call TESTA(?,?) }"); //设置存储过程 call为关键字.
	      proc.setString(1, "400"); //设置第一个输入参数
	      proc.setString(2, "TestFour");//设置第二个输入参数
	      proc.execute();//执行
	    }catch (SQLException ex2) {
	      ex2.printStackTrace();
	    }catch (Exception ex2) {
	      ex2.printStackTrace();
	    }finally{
	      try {
	        if(rs != null){
	          rs.close();
	          if(stmt!=null){
	            stmt.close();
	          }
	          if(conn!=null){
	            conn.close();
	          }
	        }
	      }
	      catch (SQLException ex1) {
	      }
	    }
	 }
}

结果如下:

java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_java 调用存储过程需要考虑事务吗_04

②有返回值的存储过程(非列表)

存储过程为:

CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2) AS
 BEGIN 
    SELECT i_name INTO PARA2 FROM zx_test_procedure WHERE I_ID= PARA1; 
 END TESTB;

Java调用代码如下:


import java.sql.*;

public class TestProcedureTwo {
	 public TestProcedureTwo() {}
	 public static void main(String[] args ){
	    String driver = "oracle.jdbc.driver.OracleDriver";
	    String strUrl = "jdbc:oracle:thin:@10.10.1.29:1521:testdb";
	    Statement stmt = null;
	    ResultSet rs = null;
	    Connection conn = null;
	    //CallableStatement cstmt = null;
	    try {
	      Class.forName(driver);
	      conn = DriverManager.getConnection(strUrl, "neb", "testneb");
	      CallableStatement proc = null; //创建执行存储过程的对象
	      proc = conn.prepareCall("{call TESTB(?,?) }"); //设置存储过程 call为关键字.
	      proc.setString(1, "300"); //设置第一个输入参数
	      proc.registerOutParameter(2, Types.VARCHAR); //第二个参数输出参数,是varchar类型的
	      proc.execute();//执行
	      String test = proc.getString(2);//获得输出参数
	      System.out.println(test);
	    }catch (SQLException ex2) {
	      ex2.printStackTrace();
	    }catch (Exception ex2) {
	      ex2.printStackTrace();
	    }finally{
	      try {
	        if(rs != null){
	          rs.close();
	          if(stmt!=null){
	            stmt.close();
	          }
	          if(conn!=null){
	            conn.close();
	          }
	        }
	      }
	      catch (SQLException ex1) {
	      }
	    }
	 }
}



结果如下:

TestThree

注意,这里的proc.getString(2)中的数值2并非任意的,而是和存储过程中的out列对应的,如果out是在第一个位置,那就是proc.getString(1),如果是第三个位置,就是proc.getString(3),当然也可以同时有多个返回值,那就是再多加几个out参数了。

③返回列表



由于oracle存储过程没有返回值,它的所有返回值都是通过out参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage了.所以要分两部分,


1, 建一个程序包。如下:


create or replace package testpackage as  
 
 type test_cursor is ref cursor;  
 end testpackage;

2,建立存储过程,存储过程为:


create or replace procedure testc(p_cursor out testpackage.test_cursor) is  
 
 begin   
open p_cursor for select * from zx_test_procedure;   
 end testc;

可以看到,它是把游标(可以理解为一个指针),作为一个out 参数来返回值的。



Java调用代码:


import java.sql.*;

public class TestProcedureThree {
	 public TestProcedureThree() {}
	 public static void main(String[] args ){
	    String driver = "oracle.jdbc.driver.OracleDriver";
	    String strUrl = "jdbc:oracle:thin:@10.10.1.29:1521:testdb";
	    Statement stmt = null;
	    ResultSet rs = null;
	    Connection conn = null;
	    //CallableStatement cstmt = null;
	    try {
	      Class.forName(driver);
	      conn = DriverManager.getConnection(strUrl, "neb", "testneb");
	      CallableStatement proc = null; //创建执行存储过程的对象
	      proc = conn.prepareCall("{call TESTC(?) }"); //设置存储过程 call为关键字.
	      //设置输出参数是一个游标.第一个参数,游标类型
	      proc.registerOutParameter(1, oracle.jdbc.OracleTypes.CURSOR);
	      proc.execute();
	      rs = (ResultSet) proc.getObject(1);
	      while(rs.next()) {
	    	  System.out.println(rs.getString(1) + ",,," + rs.getString(2));
	      }
	    }catch (SQLException ex2) {
	      ex2.printStackTrace();
	    }catch (Exception ex2) {
	      ex2.printStackTrace();
	    }finally{
	      try {
	        if(rs != null){
	          rs.close();
	          if(stmt!=null){
	            stmt.close();
	          }
	          if(conn!=null){
	            conn.close();
	          }
	        }
	      }
	      catch (SQLException ex1) {
	      }
	    }
	 }
}

结果如下:

100,,,TestOne 
 
 200,,,TestTwo  
 300,,,TestThree  
 400,,,TestFour



参考资料:

SELECT INTO STATEMENT
   将select查询的结果存入到变量中,可以同时将多个列存储多个变量中,必须有一条
   记录,否则抛出异常(如果没有记录抛出NO_DATA_FOUND)
   例子: 
   BEGIN
   SELECT col1,col2 into 变量1,变量2 FROM typestruct where xxx;
   EXCEPTION
   WHEN NO_DATA_FOUND THEN
       xxxx;
   END;
   ...



关于oracle存储过程的若干问题备忘

1.在oracle中,数据表别名不能加as,如:



java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

select a.appname    from appinfo a; 
  -- 
   正确 
  
   select a.appname  
  from appinfo  
  as a; 
  -- 
  错误  也许,是怕和oracle中的存储过程中的关键字as冲突的问题吧  
 2.在存储过程中,select某一字段时,后面必须紧跟into,如果select整个记录,利用游标的话就另当别论了。 

   
     select af.keynode    into kn  
  from APPFOUNDATION af  
  where af.appid 
  =aid  
  and af.foundationid 
  =fid; 
  -- 
   有into,正确编译 
  
     select af.keynode    from APPFOUNDATION af  
  where af.appid 
  =aid  
  and af.foundationid 
  =fid; 
  -- 
   没有into,编译报错,提示:Compilation  
  
  Error: PLS   -   00428: an    INTO clause    is expected  
  in this  
  SELECT statement

3.在利用select...into...语法时,必须先确保数据库中有该条记录,否则会报出"no data found"异常。


select count(*) from 查看数据库中是否存在该记录,如果存在,再利用select...into...

4.在存储过程中,别名不能和字段名称相同,否则虽然编译可以通过,但在运行阶段会报错



java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

select keynode    into kn    from APPFOUNDATION  
  where appid 
  =aid  
  and foundationid 
  =fid; 
  -- 
   正确运行 
  
   select af.keynode    into kn    from APPFOUNDATION af  
  where  
  af.appid 
  = 
  appid  
  and  
  af.foundationid 
  = 
  foundationid; 
  -- 
   运行阶段报错,提示 
  
ORA   -   01422:exact    fetch    returns more than requested    number  
  of rows

java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

5.在存储过程中,关于出现null的问题


假设有一个表A,定义如下:


java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

create    table A(   
id    varchar2(   50)    primary    key    not    null, 
  
vcount    number(   8)    not    null,   
bid    varchar2(   50)    not    null    --    外键


java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

); 如果在存储过程中,使用如下语句:


java 调用存储过程需要考虑事务吗 java程序调用oracle存储过程_oracle_05

select sum(vcount) into fcount from A    where 如果A表中不存在bid="xxxxxx"的记录,则fcount=null(即使fcount定义时设置了默认值,如:fcount number(8):=0依然无效,fcount还是会变成null),这样以后使用fcount时就可能有问题,所以在这里最好先判断一下:  
   
if fcount    is    null then   
    fcount:=0;   
end    if;   这样就一切ok了。  
 6.Hibernate调用oracle存储过程 

   
           this.pnumberManager.getHibernateTemplate().execute(   
                   new HibernateCallback()    ...   {
                    public Object doInHibernate(Session session)
                            throws HibernateException, SQLException ...{
                        CallableStatement cs = session
                                .connection()
                                .prepareCall("{call modifyapppnumber_remain(?)}");
                        cs.setString(1, foundationid);
                        cs.execute();
                        return null;
                    }
                });