您的位置:首页 > 数据库 > Oracle

j2ee调用Oracle带数组参数和游标的存储过程方法

2013-01-17 00:00 1121 查看
环境:Oracle 10g; jboss4.2.2;jdk1.6;hibernate 3.2

需求:有一个数据量比较大的表tableA,大概有几十万数据。里面存放用户手机号码,现在要求批量保存至少几百的的手机号码,保存之前需要分别验证这些手机号码是否在数据库中已存在。

思路:1)、在每个号码保存之前,查询数据库,是不是已经有了。

缺点:每次保存之前都要查询数据库,与数据库交互过于频繁,效率非常差;

2)、在批量保存之前,把所有的手机号查出来,放到服务器内存;然后在内存中分别对需 要保存的手机号进行校验,过滤出需要保存号码,然后在进行批量保存;

优点:减少了与数据库交互的次数;节省了系统资源

缺点:在数据量少的情况下可以使用该方法,但是几十万条的数据都要放到内存中 个,一是浪费系统内存空间,导致程序运行缓慢。也不可取。

3)、在保存之前,利用in来查询库中存在的手机号码,然后在把查询出来手机号分别与需要保存的的手 机号做对比,在查询出的手机号列表中存在的,则过滤到,然后在批量保存;

优点:相比1、2点来说这个方法比较好一些,适合保存数据不多的情况下;

确定:如果一次性需要保存号码很多的比如几百条,几千条的时候,效率依然很差。

4)、利用临时表:在数据库中创建一个临时表(事务级);然后在建立一个存储过程;在进行数据保存 时将需要保存的手机号码一次性传入存储过程中,在存储过程中先将需要保存的号码插入到临时表 中,然后在利用临时表关联实际表,查出表中已存在的号码,然后返回给程序,在程序中根据返回 的手机号码列表进行重复性过滤;

优点:速度快,可以应对大数据量的数据操作。节省资源。

缺点:如果业务发生变化,需要同时维护程序和存储过程代码。程序在进行存储过程调用时,不方 便调试。

综上所述:对于大数据量而言,利用第四点比较可取。现列出操作方法:

一、建立存储过程:(数据库中操作)

1、声明type类型,即建立数据数组类型:

create or replace type mobileArray as table of varchar2(30);

(补充:进行数据类型创建时有两种方式:

1、固定长度数组:创建时需要制定长度:create or replace
类型名 AS VARRAY(52) OF VARCHAR2(20);

2、嵌套表:可变长度数组:create or replace type
类型名 as table of varchar2(30);

本实例使用嵌套表。)

2、创建临时表:create global temporary table TEMP_SEARCH_SUBSCRIBE_MOBILE(mobile VARCHAR2(30))

on commit delete rows;

(补充:
临时表分为SESSION、TRANSACTION两种,SESSION级的临时表数据在整个SESSION都存在,直到结束此次SESSION;而TRANSACTION级的临时表数据在TRANACTION结束后消失,即COMMIT/ROLLBACK或结束SESSION都会清除TRANACTION临时表数据。

两种临时表的语法:

create global temporary table 临时表名 on commit preserve|delete rows 用preserve时就是SESSION级的临时表,用delete就是TRANSACTION级的临时表;


3、建立存储过程:

create or replace procedure proc_query_subsceibe_mobiles(mobileList in mobileArray,cur_mobileList out sys_refcursor)

as

--c number;

begin

for i in 1..mobileList.count loop

insert into TEMP_SEARCH_SUBSCRIBE_MOBILE(MOBILE) values(mobileList(i));

end loop;

open cur_mobileList for

select tempSub.MOBILE from TEMP_SEARCH_SUBSCRIBE_MOBILE tempSub

where exists (Select 1 from mobile_subscribe_info msi

where msi.user_mobile = tempSub.Mobile

and msi.OPERATION_TYPE='1' and (msi.OPRCODE <> '04' or msi.SUBSCRIBE_STATUS <> 2));

--select count(*) into c from TEMP_SEARCH_SUBSCRIBE_MOBILE;

-- dbms_output.put_line('查询到的数据个数: '||c);

-- commit;

end proc_query_subsceibe_mobiles;

4、建立测试代码:测试存储过程的重要性

declare

cur_calling sys_refcursor;

my_tbl mobileArray := mobileArray('13937025312', '13937025313', '13937025314');

rec_next varchar2(30);

begin

proc_query_subsceibe_mobiles(my_tbl,cur_calling); --这样这个游标就有值了

loop

fetch cur_calling into rec_next;

exit when cur_calling%notfound;

dbms_output.put_line(rec_next);

end loop;

end;

二、程序中调用存储过程:

1、spring jdbcTemplate调用存储过程实例:

public List<String> getSubscribeMobileList(Map<String,Object> map) {

final List<String> mobileList = (List<String>) map.get("mobiles");

final JdbcTemplate jdbcTemplateMehtod = this.jdbcTemplate;

List resultList = (List) jdbcTemplate.execute(new CallableStatementCreator() {

public CallableStatement createCallableStatement(Connection conn) throws SQLException {

String procSql="{Call proc_query_subsceibe_mobiles(?,?)}";// 调用的sql

CallableStatement proc = conn.prepareCall(procSql);

Connection oracleConn = conn.getMetaData().getConnection();

oracle.sql.ArrayDescriptor mobileArrayDes =

oracle.sql.ArrayDescriptor.createDescriptor("MOBILEARRAY", oracleConn);

oracle.sql.ARRAY mobileArray = new oracle.sql.ARRAY(mobileArrayDes, oracleConn, mobileList.toArray());

String[] array = (String[]) mobileArray.getArray();

proc.setArray(1, mobileArray);

proc.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);//输出参数

return proc;

}

}, new CallableStatementCallback() {

public Object doInCallableStatement(CallableStatement cs) throws SQLException,DataAccessException {

List<String> mobilesList = new ArrayList<String>();

cs.execute();

ResultSet rs = (ResultSet) cs.getObject(2);// 获取游标一行的值

while (rs.next()) {// 转换每行的返回值到Map中

String mobile = rs.getString("MOBILE");

if(!StringUtils.isEmpty(mobile)&&!mobilesList.contains(mobile)){

mobilesList.add(mobile);

}

}

rs.close();

return mobilesList;

}

});

return resultList;

}

2、纯jdbc调用实例:

public List<String> getSubscribeMobileList2(Map<String,Object> map) {

List<String> mobilesList = new ArrayList<String>();

List<String> mobileList = (List<String>) map.get("mobiles");

ResultSet rs=null;

String driver = "oracle.jdbc.driver.OracleDriver";

String strUrl = "jdbc:oracle:thin:
@127.0.0.1 :1521:orcl";

Connection conn = null;

try {

Class.forName(driver);

} catch (ClassNotFoundException e) {

e.printStackTrace();

}

try {

conn = DriverManager.getConnection(strUrl, "xy_mms", "xy_mms");

conn.setAutoCommit(false);

String procSql="{Call proc_query_subsceibe_mobiles(?,?)}";

CallableStatement proc = conn.prepareCall(procSql);

oracle.sql.ArrayDescriptor mobileArrayDes =

oracle.sql.ArrayDescriptor.createDescriptor("MOBILEARRAY",conn.getMetaData().getConnection());

oracle.sql.ARRAY mobileArray = new oracle.sql.ARRAY(mobileArrayDes, conn.getMetaData().getConnection(), mobileList.toArray());

proc.setArray(1, mobileArray);

proc.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);//输出参数

proc.execute();

rs = (ResultSet) proc.getObject(2);

while(rs.next()){

mobilesList.add(rs.getString("MOBILE"));

}

conn.commit();

proc.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return mobilesList;

}

3、hibernate 调用存储过程:

public List<String> getSubscribeMobileList2(Map<String,Object> map) {

List<String> mobilesList = new ArrayList<String>();

List<String> mobileList = (List<String>) map.get("mobiles");

ResultSet rs=null;

Session session = this.getSession();

Connection conn = session.connection();

try {

conn.setAutoCommit(false);

String procSql="{Call proc_query_subsceibe_mobiles(?,?)}";

CallableStatement proc = conn.prepareCall(procSql);

oracle.sql.ArrayDescriptor mobileArrayDes =

oracle.sql.ArrayDescriptor.createDescriptor("MOBILEARRAY",conn.getMetaData().getConnection());

oracle.sql.ARRAY mobileArray = new oracle.sql.ARRAY(mobileArrayDes, conn.getMetaData().getConnection(), mobileList.toArray());

proc.setArray(1, mobileArray);

proc.registerOutParameter(2, oracle.jdbc.OracleTypes.CURSOR);//输出参数

proc.execute();

rs = (ResultSet) proc.getObject(2);

while(rs.next()){

mobilesList.add(rs.getString("MOBILE"));

}

conn.commit();

proc.close();

conn.close();

} catch (SQLException e) {

e.printStackTrace();

}

return mobilesList;

}

需要注意:

1.关于字符集:11g的jdbc驱动叫orai18n.jar,之前是nls_charset.jar/classes12.jar

2.ArrayDescriptor:java传入oracle的数组需要处理一下

3.oracle.jdbc.OracleTypes.CURSOR:java获得oracle的游标。

4、

oracle.sql.ArrayDescriptor.createDescriptor("MOBILEARRAY",conn.getMetaData().getConnection());该剧中的MOBILEARRAY一定要为大写,否则会报错误;该值就是在第一步创建的的oracle type数组。

5、在运行程序时,可能会发现没有查询到数据,这是任务,在进行创建Oracle array数组是,传递过来的mobiles数组没有正确状态,此时需要查看系统中是否引入了nls_charset12.jar(Oracle 11g以前使用该包,以后的需要使用
orai18n.jar;两个都可以在Oracle安装目录中搜索得到),缺少该jar包,则无法正常装载字符串数组值。将其进入至库中即可。

6、以上都准备好以后,分别运行时发现,只有第二种利用jdbc的可以正常运行,其他两种会报,OracleConnect类转化异常。

由于本例使用的是jboss,在该例中解决方案是把jboss服务器中deploy中的项目发布包中的ojdbc14.jar和nls_charset12.jar都删掉,将这个两个jar包移动到jboss 的lib包中即可。

PS:在使用hibernate时,由于session.connect方法已被丢弃,所以,可以考虑换一种方法使用doWork方法:

Session session = this.getSession();

Work work = new Work(){

@Override

public void execute(Connection conn) throws SQLException {

ResultSet rs=null;

try {

conn.setAutoCommit(false);//此处需要禁止连接的自动提交,否则会取不到值

String procSql="{Call proc_query_subsceibe_mobiles(?,?,?,?)}";

CallableStatement proc = conn.prepareCall(procSql);

oracle.sql.ArrayDescriptor mobileArrayDes =

oracle.sql.ArrayDescriptor.createDescriptor("MOBILEARRAY",conn.getMetaData().getConnection());

oracle.sql.ARRAY mobileOralceArray = new oracle.sql.ARRAY(mobileArrayDes, conn.getMetaData().getConnection(), needSaveMobileArray.toArray());

proc.setArray(1, mobileOralceArray);

proc.setString(2, finalOperationType);

proc.setString(3, queryFlag);

proc.registerOutParameter(4, oracle.jdbc.OracleTypes.CURSOR);//输出参数

proc.execute();

rs = (ResultSet) proc.getObject(4);

while(rs.next()){

mobilesList.add(rs.getString("MOBILE"));

}

conn.commit();//提交事务,清除临时表数据

proc.close();

conn.setAutoCommit(true);//此处需要打开自动提交功能,否则,下面的事务不会提交到数据库中

} catch (SQLException e) {

e.printStackTrace();

}

}

};

session.doWork(work);
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  j2ee存储过程