MDA/MDD/TDD/DDD/DDDDDDD
posts - 536, comments - 111, trackbacks - 0, articles - 0
  BlogJava :: 首页 :: 新随笔 :: 联系 :: 聚合  :: 管理

java调oracle存储过程

Posted on 2009-08-12 11:46 leekiang 阅读(1207) 评论(2)  编辑  收藏 所属分类: oraclejdbc、事务、并发
        OracleCallableStatement cst = null;
        int oracleId = CharacterSet.ZHS16GBK_CHARSET;
        oracle.sql.CharacterSet dbCharset = oracle.sql.CharacterSet.make(oracleId);
            cst = (OracleCallableStatement) conn
                    .prepareCall("begin ?:= pkg_test.f_getList(?); end;");
//String sql = "{?=call PckgStudSltCourse.addStudPreSltCourse(?,?,?,?)}";也可以这样写
//sql="{call sp(?,?,?,?,?)}";//如果无返回值
            cst.registerOutParameter(1, OracleTypes.ARRAY, "T_ARRAY");//第一个问号表示返回结果
            cst.setString(2, userid);//第二个问号
            cst.executeUpdate();//哪怕是个查询也用executeUpdate

            oracle.sql.ARRAY simpleArray = cst.getARRAY(1);//从statement获取,而不是rs
            String[] values = (String[]) simpleArray.getArray();
            for (int i = 0; i < values.length; i++) {
                oracle.sql.CHAR out_value = new oracle.sql.CHAR(values[i],dbCharset);
                System.out.println(out_value.stringValue());
            }
            
注意:在new oracle.sql.CHAR处,可能会报
java.lang.NoClassDefFoundError: oracle/gss/util/NLSError
    at oracle.sql.CharacterSetUnknown.failCharsetUnknown(CharacterSetFactoryThin.java:178)
    at oracle.sql.CharacterSetUnknown.convert(CharacterSetFactoryThin.java:145)
    at oracle.sql.CHAR.(CHAR.java:147)
    即missing some jar file in runtime environment
    原因是weblogic没有加载web应用下的classes12.jar,而是加载了weblogic81\server\lib里的ojdbc14.jar,
    而ojdbc14.jar里没有oracle.gss.util.NLSError。
    修改classpath先加载classes12.jar,打印出来的是乱码,只出现乱码,这次没有出现类似这样的异常java.sql.SQLException:   Non   supported   character   set:   oracle-character-set-850  。
    还需要修改classpath先加载nls_charset12.jar;(必须这样,光放在web应用的lib下或光放在weblogic81\server\lib都
    不行,jar包放置或加载的这三种方式是有区别的)
问题:如果使用的是ojdbc.jar,我觉得可能就不要nls_charset12.jar了,并且不需要new oracle.sql.CHAR(values[i],dbCharset)来转换
    
http://topic.csdn.net/t/20051110/17/4385336.html
    类是通过类加载器classloader载入的。  
  缺省情况下web容器遵循java的标准标准类载入机制   --   由现载入父加载器level的类。  
  weblogic的web容器的classloader继承自ejb容器的classloader,ejb容器的classloader又继承自 application   classloader--该loader负责加载classpath下面的类,所以缺省情况下classpath下面的类会被优先载入,即使相同的类存在于web应用的lib目录。  
  可以通过配置文件来修改这种加载顺序,使得lib目录中的类得到优先调用,在weblogic   8.1中,方法是在weblogic.xml中加入下面的代码段:  
  <container-descriptor>  
  <prefer-web-inf-classes>true</prefer-web-inf-classes>  
  </container-descriptor>   
  weblogic   的加载顺序就是weblogic   classpath优先?
 
 
  一下见http://www.javaeye.com/topic/21141
  ClassNotFoundException发生在装入阶段。
当应用程序试图通过类的字符串名称,使用常规的三种方法装入类,但却找不到指定名称的类定义时就抛出该异常。

NoClassDefFoundError: 当目前执行的类已经编译,但是找不到它的定义时

也就是说你如果编译了一个类B,在类A中调用,编译完成以后,你又删除掉B,运行A的时候那么就会出现这个错误
当你使用字符串去转换类,也就是尝试使用Class.forName等方法去获得一个类的时候,如果这个类不存在,就会抛出ClassNotFoundException。
   而你编译的类无错,但是在运行时刻,缺乏某些必须的类时,就是抛出NoClassDefFoundError。这种情况最常见就是你在编译时,在classpath下有这个类,但是在运行时,你的classpath缺少这个类。
   
  加载时从外存储器找不到需要的class就出现ClassNotFoundException
  连接时从内存找不到需要的class就出现NoClassDefFoundError
  问题:加载和连接的区别

创建测试用表

CREATETABLE T_TEST(
I_ID
NVARCHAR(20),
I_NAME
NVARCHAR(20)
)

一:无返回值的存储过程

1、建立存储过程
CREATE OR REPLACE PROCEDURE TESTA(PARA1 IN VARCHAR2,PARA2 IN VARCHAR2) AS
BEGIN
   INSERT INTO T_TEST (I_ID,I_NAME) VALUES (PARA1, PARA2);
END TESTA;

2、相应的JAVA程序
import java.sql.*;
import java.io.OutputStream;
import java.io.Writer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import oracle.jdbc.driver.*;
public class TestProcedureOne {
    public TestProcedureOne() {
      }
      public static void main(String[] args ){
        String driver = "oracle.jdbc.driver.OracleDriver";
        String strUrl = "jdbc:oracle:thin:@192.168.10.216:1521:ctbu";
        Statement stmt = null;
        ResultSet rs = null;
        Connection conn = null;
        CallableStatement cstmt = null;
        try {
          Class.forName(driver);
          conn = DriverManager.getConnection(strUrl, "dbname", "password");
          CallableStatement proc = null;
          proc = conn.prepareCall("{ call dbname.TESTA(?,?) }");
          proc.setString(1, "100");
          proc.setString(2, "TestOne");
          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) {
          }
        }
      }
    }

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

1、存储过程为
CREATE OR REPLACE PROCEDURE TESTB(PARA1 IN VARCHAR2,PARA2 OUT VARCHAR2) AS
BEGIN
   SELECT INTO PARA2 FROM TESTTB WHERE I_ID= PARA1;
END TESTB;

2、JAVA代码
public class TestProcedureTWO {
public TestProcedureTWO() {
}
public static void main(String[] args ){
    String driver = "oracle.jdbc.driver.OracleDriver";
    String strUrl = "jdbc:oracle:thin:@192.168.10.216:1521:ctbu";
    Statement stmt = null;
    ResultSet rs = null;
    Connection conn = null;
    try {
      Class.forName(driver);
      conn = DriverManager.getConnection(strUrl, "dbname", "password");
      CallableStatement proc = null;
      proc = conn.prepareCall("{ call HYQ.TESTB(?,?) }");
      proc.setString(1, "100");
      proc.registerOutParameter(2, Types.VARCHAR);
      proc.execute();
      String testPrint = proc.getString(2);
      System.out.println("=testPrint=is="+testPrint);
    }
    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) {
      }
    }
}
}
}
注意,这里的proc.getString(2)中的数值2并非任意的,而是和存储过程中的out列对应的,如果out是在第一个位置,那就是 proc.getString(1),如果是第三个位置,就是proc.getString(3),当然也可以同时有多个返回值,那就是再多加几个out 参数了。

三:返回列表
由于oracle存储过程没有返回值,它的所有返回值都是通过out参数来替代的,列表同样也不例外,但由于是集合,所以不能用一般的参数,必须要用pagkage了.所以要分两部分。
1、在SQL*PLUS中建一个程序包

CREATE OR REPLACE PACKAGE TESTPACKAGE AS
TYPE Test_CURSOR IS REF CURSOR;
procedure TESTC(cur_ref out Test_CURSOR);
end TESTPACKAGE;

建立存储过程,存储过程为:
create or replace package body TESTPACKAGE as
procedure TESTC(cur_ref out Test_CURSOR) is
begin  
OPEN cur_ref FOR SELECT * FROM T_TEST;
end TESTC;
END TESTPACKAGE;
可以看到,它是把游标(可以理解为一个指针),作为一个out 参数来返回值的。
JAVA程序如下:

import java.sql.*;
import java.io.OutputStream;
import java.io.Writer;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import oracle.jdbc.driver.*;

public class TestProcedureOne {
    public TestProcedureOne() {
      }
      public static void main(String[] args ){
        String driver = "oracle.jdbc.driver.OracleDriver";
        String strUrl = "jdbc:oracle:thin:@192.168.10.216:1521:ctbu";
        Statement stmt = null;
        ResultSet rs = null;
        Connection conn = null;
        CallableStatement cstmt = null;
        try {
          Class.forName(driver);
          conn = DriverManager.getConnection(strUrl,"databasename" "password");
          CallableStatement proc = null;
          proc = conn.prepareCall("{ call cqsb.TESTA(?,?) }");
          proc.setString(1, "100");
          proc.setString(2, "TestOne");
          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) {
          }
        }
      }
    }

特别注意:
1、在执行前一定要先把oracle的驱动包放到class路径里。
2、Toad在我建立存储过程中搞了很多莫名的错误,多数是没有创建成功而不报错,
或者是创建有误而不提示,应当引起重视。所以最好还是在SQL*PLUS玩这些。
3、在SQL*PLUS中的换行是无效的,要换行的时候一定要空格结尾,特别是你直接复制代码的时候!



评论

# re: java调oracle存储过程  回复  更多评论   

2010-01-12 19:18 by leekiang
//如果java代码是utf-8编码,则不需要ZHS16GBK_CHARSET和new oracle.sql.CHAR(values[i],dbCharset)了:
如下:
ARRAY a= cst.getARRAY(1);
Datum[] data = a.getOracleArray();
for (int i = 0; i < data.length; i++) {
System.out.println(
new String(data[i].shareBytes()));
}

# re: java调oracle存储过程  回复  更多评论   

2010-01-12 19:24 by leekiang

http://zhouyq.javaeye.com/blog/240440

只有注册用户登录后才能发表评论。


网站导航: