Spring调用ORACLE存储过程的结果
oracle对于高级特性总是与众不同(我极度力讨厌这一点,如果使用它的产品就要对这种产品
进行特定的编程,这也是我从不看好weblogic之类的平台的原因),大对象存取一点要用它自己
的LOB对象,所幸我还能通过LONGRAW来代替.以便能使程序不需要特定的编码.但对于存储过程
(我是说返回结果集的存储过程),我还没有什么方法能用一个通用的程序来处理ORACLE.太多的
教材或文章在讲存储过程的调用只是不负责任地简单执行一些涵数或无结果返回的存储过程,
使大多数读者根本不知道到底如何调用存储过程的结果集.而在Spring中,根本就没有真正完全
地介绍对存储过程的结果集的处理,更别说象oracle这种"特别"的存储过程的结果集处理.
先来简单看一下我们如何在JDBC中处理存储过程的结果集的通用流程:
1.获取CallableStatement语句:
CallableStatementcs=conn.prepareCall("{callspName(?,?,?)}");
2.传入输入参数和注册输出参数
cs.setXXX(index,value);//输入参数
cs.registerOutParameter(index,type);//输出参数
3.执行存储过程:
cs.execute();
4.处理结果集.具体请参见前面的文章
以上是对于通用的存储过程返回的结果集的处理,而oracle,它不能返回结果集,只能在输出参数中
返回一个cursor,所以通用的流程中你获取不到任何结果:
packagePK_AREA_PUBLICis
TYPEserarch_resultISREFCURSOR;
PROCEDUREarea_search(vTarget_inINVARCHAR2,cur_result_outOUTserarch_result);
endPK_AREA_PUBLIC;
packagebodyPK_AREA_PUBLICis
PROCEDUREarea_search(vTarget_inINVARCHAR2,cur_result_outOUTserarch_result)
IS
sqlstrVARCHAR2(1000);
BEGIN
sqlstr:='select.................................';
OPENcur_result_outFORsqlstrUSINGvTarget_in;
ENDarea_search;
endPK_AREA_PUBLIC;
对于上面的例子,存储过程有一个输入参数,一个输出参数,我们要接受输出参数作为结果集处理.所
以注册的时候应该注册为:
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);//输出参数
这样在存储过程执行后,获取输出数造型为ResultSet就可以处理:
ResultSetrs=(ResultSet)cs.getObject(2);
如果有多个结果集就用多个输出参数.
明白了ORACLE的特殊性,我们再看看在spring中如果处理它的存储过程的结果集:
spring在处理复杂对象的时候,大都采用回调的方法,要求程序员自己实现接口方法.也就是它提供了
程序运行时的参数,要求你自己对这些参数进行处理.对于JdbcTemplate,它在很多地方提供了ResultSet
参数供程序员处理.在Spring文档中提供了对于通用流程,也就是从存储过程执行结果中获取结果集的
例程:
Mapout=execute(newHashMap());
其实它是默认实现了上面JDBC通用流程中对ResuleSet到Map的封装.而对于Oracle,我们就必须自己手
实现对输出参数中ResultSet的回调:
publicclassSpringStoredProcedure
extendsStoredProcedure{
publicArrayList<HashMap>set=newArrayList<HashMap>();
//声明一个用于接收结果集的数据结构,其中的元素为row,用map存放
privateMapinParam;//输入参数
privateRowMapperrm=newRowMapper(){
publicObjectmapRow(ResultSetrs,introwNum)throwsSQLException{
returnnull;//不用从存储过程本身获取结果
}
};
privateRowMapperResultReadercallback=newRowMapperResultReader(rm){
publicvoidprocessRow(ResultSetrs)//回调处理
throwsSQLException{
intcount=rs.getMetaData().getColumnCount();
String[]header=newString[count];
for(inti=0;i<count;i++)
header[i]=rs.getMetaData().getColumnName(i+1);
while(rs.next()){
HashMap<String,String>row=newHashMap(count+7);
for(inti=0;i<count;i++)
row.put(header[i],rs.getString(i+1));
set.add(row);
}
}
};//RowMapperResultReader作为输出参数的回调句柄
publicSpringStoredProcedure(DataSourceds,StringSQL){
setDataSource(ds);
setSql(SQL);
}
publicvoidsetOutParameter(Stringcolumn,inttype){
declareParameter(newSqlOutParameter(column,type,callback));
//利用回调句柄注册输出参数
}
publicvoidsetParameter(Stringcolumn,inttype){
declareParameter(newSqlParameter(column,type));
}
publicvoidSetInParam(MapinParam){
this.inParam=inParam;
}
publicMapexecute(){
compile();
returnexecute(this.inParam);
}
}
下面我们看一下调用过程:
DriverManagerDataSourceds=.......;
SpringStoredProceduresp=newSpringStoredProcedure(ds,"PK_AREA_PUBLIC.area_search");
//注册参数类型,输入参数和输出参数同时注册,否则不能正确编译存储过程
sp.setParameter("vTarget_in",java.sql.Types.VARCHAR);
sp.setOutParameter("cur_result_out",oracle.jdbc.OracleTypes.CURSOR);
sp.compile();
//传入输入参数值
Mapin=newHashMap();
in.put("vTarget_in","一个内容");
sp.SetInParam(in);
//执行存储过程
sp.execute();
Mapm=sp.set.get(0);//ReultSet的第一条记录
//set定义为SpringStoredProcedure的属性用于接收回调时的数据
//如果有多个输出参数,应该在每个输出参数的回调方法中生成该输出
//参数对应的ArrayList,然后加到一个成员变量的数据结构中.
Iteratori=m.keySet().iterator();
while(i.hasNext()){
Stringkey=i.next().toString();
System.out.println(key+"=>"+m.get(key));
}
总之,上面的方法虽然解决了Spring中对Oracle存储过程的调用,但我极力不推荐这程复杂的处理
oracle对于高级特性总是与众不同(我极度力讨厌这一点,如果使用它的产品就要对这种产品
进行特定的编程,这也是我从不看好weblogic之类的平台的原因),大对象存取一点要用它自己
的LOB对象,所幸我还能通过LONGRAW来代替.以便能使程序不需要特定的编码.但对于存储过程
(我是说返回结果集的存储过程),我还没有什么方法能用一个通用的程序来处理ORACLE.太多的
教材或文章在讲存储过程的调用只是不负责任地简单执行一些涵数或无结果返回的存储过程,
使大多数读者根本不知道到底如何调用存储过程的结果集.而在Spring中,根本就没有真正完全
地介绍对存储过程的结果集的处理,更别说象oracle这种"特别"的存储过程的结果集处理.
先来简单看一下我们如何在JDBC中处理存储过程的结果集的通用流程:
1.获取CallableStatement语句:
CallableStatementcs=conn.prepareCall("{callspName(?,?,?)}");
2.传入输入参数和注册输出参数
cs.setXXX(index,value);//输入参数
cs.registerOutParameter(index,type);//输出参数
3.执行存储过程:
cs.execute();
4.处理结果集.具体请参见前面的文章
以上是对于通用的存储过程返回的结果集的处理,而oracle,它不能返回结果集,只能在输出参数中
返回一个cursor,所以通用的流程中你获取不到任何结果:
packagePK_AREA_PUBLICis
TYPEserarch_resultISREFCURSOR;
PROCEDUREarea_search(vTarget_inINVARCHAR2,cur_result_outOUTserarch_result);
endPK_AREA_PUBLIC;
packagebodyPK_AREA_PUBLICis
PROCEDUREarea_search(vTarget_inINVARCHAR2,cur_result_outOUTserarch_result)
IS
sqlstrVARCHAR2(1000);
BEGIN
sqlstr:='select.................................';
OPENcur_result_outFORsqlstrUSINGvTarget_in;
ENDarea_search;
endPK_AREA_PUBLIC;
对于上面的例子,存储过程有一个输入参数,一个输出参数,我们要接受输出参数作为结果集处理.所
以注册的时候应该注册为:
cs.registerOutParameter(2,oracle.jdbc.OracleTypes.CURSOR);//输出参数
这样在存储过程执行后,获取输出数造型为ResultSet就可以处理:
ResultSetrs=(ResultSet)cs.getObject(2);
如果有多个结果集就用多个输出参数.
明白了ORACLE的特殊性,我们再看看在spring中如果处理它的存储过程的结果集:
spring在处理复杂对象的时候,大都采用回调的方法,要求程序员自己实现接口方法.也就是它提供了
程序运行时的参数,要求你自己对这些参数进行处理.对于JdbcTemplate,它在很多地方提供了ResultSet
参数供程序员处理.在Spring文档中提供了对于通用流程,也就是从存储过程执行结果中获取结果集的
例程:
Mapout=execute(newHashMap());
其实它是默认实现了上面JDBC通用流程中对ResuleSet到Map的封装.而对于Oracle,我们就必须自己手
实现对输出参数中ResultSet的回调:
publicclassSpringStoredProcedure
extendsStoredProcedure{
publicArrayList<HashMap>set=newArrayList<HashMap>();
//声明一个用于接收结果集的数据结构,其中的元素为row,用map存放
privateMapinParam;//输入参数
privateRowMapperrm=newRowMapper(){
publicObjectmapRow(ResultSetrs,introwNum)throwsSQLException{
returnnull;//不用从存储过程本身获取结果
}
};
privateRowMapperResultReadercallback=newRowMapperResultReader(rm){
publicvoidprocessRow(ResultSetrs)//回调处理
throwsSQLException{
intcount=rs.getMetaData().getColumnCount();
String[]header=newString[count];
for(inti=0;i<count;i++)
header[i]=rs.getMetaData().getColumnName(i+1);
while(rs.next()){
HashMap<String,String>row=newHashMap(count+7);
for(inti=0;i<count;i++)
row.put(header[i],rs.getString(i+1));
set.add(row);
}
}
};//RowMapperResultReader作为输出参数的回调句柄
publicSpringStoredProcedure(DataSourceds,StringSQL){
setDataSource(ds);
setSql(SQL);
}
publicvoidsetOutParameter(Stringcolumn,inttype){
declareParameter(newSqlOutParameter(column,type,callback));
//利用回调句柄注册输出参数
}
publicvoidsetParameter(Stringcolumn,inttype){
declareParameter(newSqlParameter(column,type));
}
publicvoidSetInParam(MapinParam){
this.inParam=inParam;
}
publicMapexecute(){
compile();
returnexecute(this.inParam);
}
}
下面我们看一下调用过程:
DriverManagerDataSourceds=.......;
SpringStoredProceduresp=newSpringStoredProcedure(ds,"PK_AREA_PUBLIC.area_search");
//注册参数类型,输入参数和输出参数同时注册,否则不能正确编译存储过程
sp.setParameter("vTarget_in",java.sql.Types.VARCHAR);
sp.setOutParameter("cur_result_out",oracle.jdbc.OracleTypes.CURSOR);
sp.compile();
//传入输入参数值
Mapin=newHashMap();
in.put("vTarget_in","一个内容");
sp.SetInParam(in);
//执行存储过程
sp.execute();
Mapm=sp.set.get(0);//ReultSet的第一条记录
//set定义为SpringStoredProcedure的属性用于接收回调时的数据
//如果有多个输出参数,应该在每个输出参数的回调方法中生成该输出
//参数对应的ArrayList,然后加到一个成员变量的数据结构中.
Iteratori=m.keySet().iterator();
while(i.hasNext()){
Stringkey=i.next().toString();
System.out.println(key+"=>"+m.get(key));
}
总之,上面的方法虽然解决了Spring中对Oracle存储过程的调用,但我极力不推荐这程复杂的处理