近期查找java调用存储过程的时候发现了一些不错的文章,以下链接就是其中之一:
http://windmxf.iteye.com/blog/1391508#comments
JAVA执行存储过程(和参数顺序无关,使用oracle数据库) 写道
开发中遇到的问题:
1.本来CallableStatement 是提供setString(ParameterName,value)这样的方法的,
--但是看了ibm网站上的资料发现不支持oracle,是infomix的特性,所以无法用,只能麻烦点用index的方式注册输出参数
2.另外所有的参数包括存储过程名称、包名都要大写,否则不认得
3.使用getProcedureColumns(pckgName,"" , proc, null);时注意
--第一个参数catalog对应oracle的包名,
--第二个参数应该是schema名称,我一开始以为是用户名,但不对,只能写空,但不要写null,
--否则会得到这个实例里面所有这个存储过程的参数,当实例存在多个用户的使用会有问题。
1.本来CallableStatement 是提供setString(ParameterName,value)这样的方法的,
--但是看了ibm网站上的资料发现不支持oracle,是infomix的特性,所以无法用,只能麻烦点用index的方式注册输出参数
2.另外所有的参数包括存储过程名称、包名都要大写,否则不认得
3.使用getProcedureColumns(pckgName,"" , proc, null);时注意
--第一个参数catalog对应oracle的包名,
--第二个参数应该是schema名称,我一开始以为是用户名,但不对,只能写空,但不要写null,
--否则会得到这个实例里面所有这个存储过程的参数,当实例存在多个用户的使用会有问题。
参考这个思路自己也写了一个,以下是我写的代码:
package com.fwy.db.util; import java.sql.CallableStatement; import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; public class ProcedureExecuter { /** * @param procedureName --[包名.]存储过程名 * @param paramList --参数列表 -name-value 参数名为大写 * @return procParam --将结果放入参数类表中返回 */ public static Map<String,Object> execute(String procedureName,Map<String,Object> paramList){ Connection conn=null; ResultSet rs =null; CallableStatement call=null; DatabaseMetaData dbmd=null; List<String> paramNames = new ArrayList<String>();//param-name List<Integer> paramTypes = new ArrayList<Integer>();//in-out type List<Object> inParamValues = new ArrayList<Object>();//param-value List<Integer> outParamTypes = new ArrayList<Integer>();//param-type try { procedureName=procedureName.toUpperCase(); conn = DBUtil.getConnection(); if(paramList==null){ call = conn.prepareCall("{ call "+procedureName+"}"); call.execute(); return null; } dbmd = conn.getMetaData(); String sqlCall="{ call "+procedureName+"("; String packageName = procedureName.lastIndexOf(".") > 0 ? procedureName.substring(0, procedureName.lastIndexOf(".")): null;// 有包体时 String procedure = procedureName.substring(procedureName.lastIndexOf(".") + 1); rs = dbmd.getProcedureColumns(packageName, "", procedure, null); //(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) while (rs.next()) {//获取参数类表 Integer columnType = rs.getInt("COLUMN_TYPE"); String columnName = rs.getString("COLUMN_NAME"); Integer dataType = rs.getInt("DATA_TYPE"); sqlCall += columnName + "=>?,"; paramTypes.add(columnType);//参数类型 in out in-out inParamValues.add(paramList.get(columnName));//in参数的值 outParamTypes.add(dataType);//out参数数据类型 paramNames.add(columnName);//参数名--大写 } sqlCall = sqlCall.substring(0, sqlCall.lastIndexOf(",")) + ")}";//调用语句 call = conn.prepareCall(sqlCall); for (int i=1;i<=paramTypes.size();i++) { Integer columnType = paramTypes.get(i-1); if (columnType == DatabaseMetaData.procedureColumnIn) {// 给in参数赋值 call.setObject(i, inParamValues.get(i-1)); } else if (columnType==DatabaseMetaData.procedureColumnOut) {// 给out参数注册数据类型 call.registerOutParameter(i, outParamTypes.get(i-1)); }else if(columnType==DatabaseMetaData.procedureColumnInOut){//给in-out参数赋值,注册数据类型 call.setObject(i, inParamValues.get(i-1)); call.registerOutParameter(i, outParamTypes.get(i-1)); } } call.execute();//执行存储过程 for (int i=1;i<=paramTypes.size();i++) { Integer paramType = paramTypes.get(i-1); if (paramType != DatabaseMetaData.procedureColumnIn) {//获取输出值放到参数列表 String name=paramNames.get(i-1); Object value=call.getObject(i); paramList.put(name, value); } } conn.commit(); } catch (SQLException e) { e.printStackTrace(); }finally{ DBUtil.close(rs, call, conn); } return paramList; } public static void main(String[] args) { String procName="findEmpById"; Map<String,Object> paramList =new HashMap<String,Object>(); paramList.put("P_ID", "gz1307001"); execute(procName, paramList); for(String key:paramList.keySet()){ System.out.println(key+":"+paramList.get(key)); } } }
PS:调用到的存储过程
create or replace procedure findEmpById (p_id in varchar2, v_name out varchar2, v_age out number,v_deptno out varchar2,v_description out varchar2 ) AS begin select name,age,deptno,description into v_name,v_age,v_deptno,v_description from emp where id=p_id; exception when no_data_found then dbms_output.put_line('not such a emploee for this id'); end findEmpById;