现在有一半的逻辑都是在存储过程中写的,从第一次使用jdbc去调用存储过程时,我就觉得传统的jdbc调用存储过程太“复杂”了,也可以说是繁琐了,复杂的不在于那些调用的代码,而是调用过程中代码里面往往都是由不确定参数个数(不确定输入参数个数、输出参数个数)、输出参数类型、使用索引的形式设置或获取参数引起的太不简便,常常都是一写一大片,别人拷贝过去也是越发感觉太乱,就如同使用传统的jdbc查询数据*作ResultSet对象取值一样,直接这么用太不科学。所以就有了本篇文章,代码封装最大的意义我认为是最大程度上简化调用,先来看一下传统的jdbc调用存储过程是怎样的,并且分析一下如果简化一下封装可能会有哪些问题要解决?调用代码参考如下:
通过上面的代码我们可以看出如果是其它存储过程在调用时同样会存在下列几个问题:
1、 调用时sql的?传入参数个数不确定;
2、 存储过程的输入和输出参数个数均不确定;
3、 输出参数的类型不确定;
4、 输出参数的参数名称不确定;
5、 如果中间加上一个输入或输出的参数,这些*作的索引全都得调整;
由于这一系列不确定因素,我看到大家在使用jdbc调用存储过程时封装的版本是具体的调用自己实现,即将*作Connection对象给包装一下,然后使用匿名内部类的形式*作CallableStatement对象,然后传入的输出和输出参数自己设置,返回的参数都是自己处理。
说了这么多没有的,写了一个简单的存储过程,分别使用传统的和我封装后的调用来看一下具体简化到了什么程度,参考如下:
测试存储过程代码
CREATE OR REPLACEPACKAGE PCKG_TEST_JDBCIS
TYPEDATA_CURSORISREFCURSOR;
--测试输入和输出参数存储过程
/*
输入用户名和密码,输出执行状态码和列表
*/
PROCEDURETEST_INOROUT_PARAM(i_usernameinvarchar2,
i_passwordinvarchar2,
o_result out varchar2,
o_dataList out DATA_CURSOR);
endPCKG_TEST_JDBC;
/
CREATE OR REPLACEPACKAGE BODY PCKG_TEST_JDBCIS
--输入和输出参数存储过程
PROCEDURETEST_INOROUT_PARAM(i_usernameinvarchar2,
i_passwordinvarchar2,
o_result out varchar2,
o_dataList out DATA_CURSOR)IS
BEGIN
if i_username ='cdd' andi_password ='cdd' then
o_result :='success';--正确
else
o_result :='input';--校验不通过
endif;
open o_dataListfor
selecti_usernameas "userName", i_passwordas "password" fromdual;
EXCEPTION
WHEN OTHERSTHEN
IF o_dataList%ISOPEN
THEN
CLOSE o_dataList;
ENDIF;
o_result :='error';--出现错误
RETURN;
ENDTEST_INOROUT_PARAM;
endPCKG_TEST_JDBC;
/
存储过程说明:以上为存储过程包定义及具体方法定义,可以只看PACKAGE BODY PCKG_TEST_JDBC部分,可以看出函数的实现较为简单,传入username和password两个参数,并且当着两个参数都为‘cdd’时,存储过程的两个输出参数为result=success,dataList中只有一条数据,两个属性值等于用户传递的username与password,否则返回result=input,dataList不变。
传统的调用及输出
其中返回Map中的result与dataList为写死的,并非从存储过程中的输出参数中获取的。
封装后的代码调用
可以看到具体的调用代码为simple.callProcedure函数,传递一个过程名称与用户名、密码的参数即可。使用者只需要关心自己定义的存储过程的输入参数值,至于输出参数则由声明时的定义为准(或者可约定一下规则),直接返回一个Map结构的键值对数据。
实现原理
根据过程名称从数据库中找出该过程的结构,即输入输出参数个数、名称及顺序,有了这个第一步先构建一个动态的{call 过程名称(?,?,?,?)}调用sql;
第二步使用Java的动态可变参数来封装,让用户可以传递任意个输入参数;
第三步根据该过程的结构构造输入参数赋值的索引,预置输出参数的oracle与Java类型对应关系;
第四步调用存储过程,根据输出参数的索引取出对应的值,并将值绑定在过程结构的输出参数的名称上;
注意:由于oracle的各种参数(结构相关的)均返回大写,我就预置了几种简单的规则,如:1、存储过程在增删改查时输出的参数只需要返回result与message即可(result为是否成功、message为对应的中文描述),查询时除了返回状态外,还需要有对应的集合列表和总记录数之类的参数,有的人喜欢定义变量使用retCode与itemList,偶尔也会使用到totalNum等,这些,一旦遇到这几种参数时的大写匹配时,我都会将其转换为驼峰的命名结构;
2、另外如果遇到匈牙利的命名时均将其转换为驼峰结构,如命名为O_DATA_LIST,会将其中开头的O_去掉,将每个_分割的部分转换为小写,开头的字母为大写,转换后的参数名为dataList,然而这些也可以不需要,为了便捷就直接在一个vo类的getter属性方法中写的,较为简单。
总结说来,代码比较简单,没什么新的东西,有兴趣可自行下载查看,小弟行走江湖这几年见到的没有比这个更简单的了,或者说在我现有的认知中已经无法被我自己超越了。注意:现在的代码并未在实践中深入检验,只是在几个示例中使用均成功,在存储过程返回number类型的参数中,返回记录集类型的参数中等。
其它说明
代码里面有使用到Apache-commons相关的jar与ojdbc需自行导入。
下载地址
如有问题可进行留言反馈。
src.zip