存储过程的调用

来源:互联网 发布:淘宝清仓女鞋 编辑:程序博客网 时间:2024/05/16 15:56

详细解释——理论知识:

对已储存过程的调用是CallableStatement对象所含的内容。

这种调用是用一种换码语法来写的,有两种形式 :一种形式带结果参,另一种形式不带结果参数。

结果参数是一种输出(OUT)参数,是已储存过程的返回值。

 两种形式都可带有数量可变的输入(IN参数)、输出(OUT参数)或输入和输出(INOUT参数)的参数。

 

问号 将用作参数的占位符。

 

在JDBC中调用已储存过程的语法如下所示。

注意,方括号表示其间的内容是可选项;方括号本身并非语法的 组成部份。

{call过程名[(?,?,...)]} 返回结果参数的过程的语法为: {?=call过程名[(?,?,...)]} 不带参数的已储存过程的语法类似: {call过程名} 通常,创建CallableStatement对象的人应当知道所用的DBMS是支持已储存过程的,并且知道这些过程都是些 什么。

 

然而,如果需要检查,多种DatabaseMetaData方法都可以提供这样的信息。例如,如果DBMS支持已储 存过程的调用,则supportsStoredProcedures方法将返回true,而getProcedures方法将返回对已储存过程的 描述。 CallableStatement继承Statement的方法(它们用于处理一般的SQL语句),还继承了PreparedStatement的 方法(它们用于处理IN参)。

 

 CallableStatement中定义的所有方法都用于处理OUT参数或INOUT参数的输出部分:注册OUT参数的JDBC类型 (一般SQL类型)、从这些参数中检索结果,或者检查所返回的值是否为JDBCNULL。

 

JDBC存储过程1、创建CallableStatement对象 CallableStatement对象是用Connection方法prepareCall创建的。

 

下例创建CallableStatement的实例,其中 含有对已储存过程getTestData调用。

 

该过程有两个变量,但不含结果参数:CallableStatementc stmt=con.prepareCall("{callgetTestData(?,?)}"); 其中?占位符为IN、OUT还是INOUT参数,取决于已储存过程getTestData。

 

JDBC存储过程2、IN和OUT参数 将IN参数传给CallableStatement对象是通过setXXX方法完成的。该方法继承自PreparedStatement。

 

所传入 参数的类型决定了所用的setXXX方法(例如,用setFloat来传入float值等)。

 

如果已储存过程返回OUT参数 ,则在执行CallableStatement对象以前必须先注册每个OUT参数的JDBC类型(这是必需的,因为某些DBMS要 求JDBC类型)。

 

注册JDBC类型是用registerOutParameter方法来完成的。

 

语句执行完后,CallableStatement 的getXXX方法将取回参数值。

 

正确的getXXX方法是为各参数所注册的JDBC类型所对应的Java类型。

换言之, registerOutParameter使用的是JDBC类型(因此它与数据库返回的JDBC类型匹配),而getXXX将之转换为 Java类型。

作为示例,下述代码先注册OUT参数,执行由cstmt所调用的已储存过程,然后检索在OUT参数中返回的值。

 

方 法getByte从第一个OUT参数中取出一个Java字节,而getBigDecimal从第二个OUT参数中取出一个BigDecimal 对象(小数点后面带三位数):

 CallableStatementc stmt=con.prepareCall("{callgetTestData(?,?)}");

cstmt.registerOutParameter (1,java.sql.Types.TINYINT);

cstmt.registerOutParameter(2,java.sql.Types.DECIMAL,3);

cstmt.executeQuery(); byte x=cstmt.getByte(1);

java.math.BigDecimaln=cstmt.getBigDecimal(2,3);

CallableStatement与ResultSet不同,它不提供用增量方式检索大OUT值的特殊机制。

JDBC存储过程

3、INOUT参数 既支持输入又接受输出的参数(INOUT参数)除了调用registerOutParameter方法外,还要求调用适当的 setXXX方法(该方法是从PreparedStatement继承来的)。

setXXX方法将参数值设置为输入参数,而 registerOutParameter方法将它的JDBC类型注册为输出参数。

setXXX方法提供一个Java值,而驱动程序先把 这个值转换为JDBC值,然后将它送到数据库中。这种IN值的JDBC类型和提供给registerOutParameter方法的 JDBC类型应该相同。

 

然后,要检索输出值,就要用对应的getXXX方法。

 

例如,Java类型为byte的参数应该使 用方法setByte来赋输入值。

应该给registerOutParameter提供类型为TINYINT的JDBC类型,同时应使用 getByte来检索输出值。

下例假设有一个已储存过程reviseTotal,其唯一参数是INOUT参数。

方法setByte把此参数设为25,驱动程序 将把它作为JDBCTINYINT类型送到数据库中。

接着,registerOutParameter将该参数注册为JDBCTINYINT。

执 行完该已储存过程后,将返回一个新的JDBCTINYINT值。

方法getByte将把这个新值作为Javabyte类型检索。

 

CallableStatementc stmt=con.prepareCall("{callreviseTotal(?)}");

 cstmt.setByte(1,25);

cstmt.registerOutParameter(1,java.sql.Types.TINYINT);

 cstmt.executeUpdate(); byte x=cstmt.getByte(1); 1)返回一个结果集(ResultSet)。

2)返回一个特定的值。  

下面来详细的说明。  

1)返回一个结果集(ResultSet),这种类似通常的处理结果集     

 

如果事先就有一个类似如下的

procedure CREATE PROCEDURE getShipQuantity

@jsid int AS SELECT jf_js_id,SUM(jf_ship_quantity)

AS

shipqty FROM tjobsheet_finish f

WHERE (jf_js_id=@jsid) GROUP BY jf_js_id

那么我们将通过如下的代码来调用   

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

Connection con = conn.connection();

ResultSet rs = null;
BigDecimal shipQuantity = new BigDecimal(0);

 try{ CallableStatement cs = con.prepareCall(sql);

cs.setInt(1,jsoId);//设置输入参数

rs = cs.executeQuery();//返回结果集

if(rs.next()){

shipQuantity = new BigDecimal(rs.getDouble(2));

}

logger.debug("shipQuantity --------------------- "+shipQuantity);

 }catch(Exception e){

logger.debug(e);

}

 

2)返回一个特定的值。

也就是说,在procedure的定义中已经用output输出参数了。

请看下面的

proceduer create procedure getSingleWgt

@@singleWgt numeric(8,3) output,@jsnum varchar(11) = '0000-0480'

as

declare @stwgt numeric(8,3)

select @stwgt = sum(b.stwgt) from js as a inner join jsactdtl as b on a.jsnum = b.jsnum

where a.completion = 1 and b.stflag = 22 and a.jsnum = @jsnum

select @@singleWgt = (@stwgt/orderedqty) from js where jsnum = @jsnum

 

那么我们将通过如下的代码来调用

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

Connection con = getSession().connection();//得到connection

try{

CallableStatement cs = con.prepareCall(sql);//通过它来执行sql

cs.registerOutParameter(1,java.sql.Types.FLOAT);//注册输出参数

cs.setString(2,shipment.getJsnum());//指出输入参数

if(cs.execute()){//执行

float output = cs.getFloat(1);//返回值

}

}catch(Exception e){

logger.debug(e);

 

例子eg:创建存储过程

create or replace procedure p_find_emp( i_emp_id in tb_employee.emp_id%type ) is v_str_emp_name tb_employee.emp_name%type;

begin

select emp_name into v_str_emp_name from tb_employee where emp_id=i_emp_id;

dbms_output.put_line('该雇员名字叫:'||v_str_emp_name);

end p_find_emp; oracle 分页

 

--创建游标

create or replace package pkg_query is type cur_result_type is ref cursor;--游标的类型

end pkg_query;

create or replace procedure p_query_page( str_page_action in varchar

 

2, ---分页动作,可以使上一页:

previous_page,

 

下一页:next_page,

 

----首页:first_page,

尾页:last_page,

指定页:page_number

str_query_table in varchar2, -----需要查询的表,可以以单表或通过连接出来的虚拟表

str_query_condition in varchar2,-----分页的查询条件

str_result_col in varchar2,-----需要输出的字段名

str_order_condition in varchar2,-----查询的排序条件

str_order_style in varchar2,-----排序的风格,升序或降序

i_page_size in out number,-------每页显示的数据条数

i_current_page in out number, ----当前页索引

i_total_record out number,-----当前符合条件的总记录条数

i_total_page out number,-----当前符合条件的总页数

cur_query_result out pkg_query.cur_result_type------查询的结果 )

is v_str_query_sql varchar2(10000):='';-----查询的sql语句

v_i_start_record number(10):=0;----起始记录位置

v_i_end_record number(10):=0;----终止记录的位置

begin

-------检验指定需要查询的表的参数是否为空

if(str_query_table is null or str_query_table = '')

 then raise_application_error(-20001,'需要查询的表不能为空');

 end if;

v_str_query_sql:='select count(*) from '||str_query_table;

------当查询的条件不为空时,将相应的查询条件拼接到sql中

if(str_query_condition is not null and str_query_condition <> '')

then v_str_query_sql:=v_str_query_sql||'where '||str_query_condition;

end if;

-----PL/Sq 动态调用sql

execute immediate v_str_query_sql into i_total_record;

--------检测每页数据量,如果小于等于零,把每页数据量设为默认值10;

if ( i_page_size <= 0 )then i_page_size := 10;

end if;

------求当前符合条件的信息的总页数

if mod(i_total_record,i_page_size)=0 then i_total_page := (i_total_record/i_page_size);

else i_total_page := trunc(i_total_record/i_page_size)+1;

end if;

------根据当前的分页动作转换当前页索引

case str_page_action when 'first_page' then i_current_page := 1;

when 'last_page' then i_current_page := i_total_page;

when 'previous_page' then i_current_page := i_current_page-1;

when 'next_page' then i_current_page := i_current_page+1;

when 'page_number' then i_current_page := i_current_page;

else i_current_page := 1; end case;

------求起始记录的索引位置和终止记录的索引位置

v_i_start_record := (i_current_page-1)*i_page_size+1;

v_i_end_record := i_current_page*i_page_size;

-----根据以上结果拼接sql语句。

v_str_query_sql:='select ';

if (str_result_col is null or str_result_col='') then raise_application_error(-20002,'需要输出的字段不能为空');

end if;

v_str_query_sql:=v_str_query_sql||str_result_col||' from '||str_query_table||' where 1=1 ';

------当查询条件不为空时,把相应的查询条件拼接到sql语句中

if (str_query_condition is not null and str_query_condition <> '')

then

v_str_query_sql:=v_str_query_sql||str_query_condition;

end if;

----当查询的条件不等于空,将查询条件拼接到sql中

if (str_order_condition is not null and str_order_condition <> '')

then

v_str_query_sql:=v_str_query_sql||' order by '||str_order_condition;

   if str_order_style is not null and str_order_style <> ''

   then v_str_query_sql:=v_str_query_sql||' '||str_order_style;

   end if;

end if;

v_str_query_sql:='select * from ( select A.*,rownum rn from ( '||v_str_query_sql ||' ) A where rownum <='||v_i_end_record||' ) B where rn >= '||v_i_start_record;

dbms_output.put_line(v_str_query_sql);

open cur_query_result for v_str_query_sql;

end p_query_page;

 

ok 现在看下怎么样调用上面的存储过程

 

package com.softeem.dbc;

 

import java.sql.CallableStatement;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import oracle.jdbc.driver.OracleTypes;

 

public class DBConnection {

private final static String DRIVER_CLASS = "oracle.jdbc.driver.OracleDriver";

private final static String URL = "jdbc:oracle:thin:@127.0.0.1:1521:orcl";

private final static String USER_NAME = "tangzheng";

private final static String PASSWORD = "123456";

public static Connection getconnection() {

Connection conn = null;
try {
Class.forName(DRIVER_CLASS);
} catch (ClassNotFoundException e) {
System.out.println("驱动加载失败");

e.printStackTrace();
}

try {
conn = DriverManager.getConnection(URL, USER_NAME, PASSWORD);
} catch (SQLException e) {
System.out.println("获取连接失败");
e.printStackTrace();
}

return conn;

}

 

public PageDTO findOnePage(String pageAction, int pagesize, int currentPage)
throws SQLException {

String table = "tb_employee emp";
String queryCondition = "emp.emp_id<15";
String resultcol = "*";
String orderCondition = "emp.emp_id";
String orderstyle = "asc";
Connection conn = getconnection();
PageDTO pageinfo = null;
try {

CallableStatement cs = conn
.prepareCall("{call p_query_page(?,?,?,?,?,?,?,?,?,?,?)}");
cs.setString(1, pageAction);
cs.setString(2, table);
cs.setString(3, queryCondition);
cs.setString(4, resultcol);
cs.setString(5, orderCondition);
cs.setString(6, orderstyle);
cs.setInt(7, pagesize);
cs.setInt(8, currentPage);

cs.registerOutParameter(7, OracleTypes.INTEGER);
cs.registerOutParameter(8, OracleTypes.INTEGER);
cs.registerOutParameter(9, OracleTypes.INTEGER);
cs.registerOutParameter(10, OracleTypes.INTEGER);
cs.registerOutParameter(11, OracleTypes.CURSOR);

cs.execute();

pageinfo = new PageDTO();

pageinfo.setCurrentPage(cs.getInt(7));
pageinfo.setCurrentPage(cs.getInt(8));
pageinfo.setTotalRecord(cs.getInt(9));
pageinfo.setTotalPage(cs.getInt(10));

ResultSet rs = (ResultSet) cs.getObject(11);

List employees = new ArrayList();

EmployeeDTO employee = null;
while (rs.next()) {

employee = new EmployeeDTO();

employee.setEmpId(rs.getInt("emp_id"));

employee.setEmpName(rs.getString("emp_name"));

employee.setSex(rs.getString("sex"));

employee.setSal(rs.getDouble("sal"));

employees.add(employee);

}
pageinfo.setResult(employees);

} finally {

if (conn != null && !conn.isClosed()) {

conn.close();

}

}
return pageinfo;

}

 

 

public static void main(String[] args) {

String pageAction = "nextPage";
int pagesize = 5;

int currentpage = 2;
DBConnection db = new DBConnection();

try {
PageDTO pageinfo = db
.findOnePage(pageAction, pagesize, currentpage);

List<EmployeeDTO> list = pageinfo.getResult();

System.out.println("总页数:" + pageinfo.getCurrentPage());
System.out.println("总记录数:" + pageinfo.getTotalRecord());
for (int i = 0; i < list.size(); i++) {

System.out.println(list.get(i).toString());
}
} catch (SQLException e) {
e.printStackTrace();
}
}

}