Java中如何将一个 List 类型的参数传入存储过程(Oracle数据库)
步骤简述
- 定义好存储过程,Java中的数组对象
- 建立数据库映射对象来映射
List
类型的数据 - Java中调用存储过程传入
List
类型的参数
存储过程
PROCEDURE PRO_PLAN (
SERIAL_NUM IN VARCHAR2, --流水号
PLAN_LIST IN PLAN_TY, --计划列表
ORIGINAL_NUM IN VARCHAR2, --原单据号
RE_CODE OUT VARCHAR2, --返回编码
RE_MSG OUT VARCHAR2 --返回信息
)
TYPE 模型映射对象
建立数据库对象来映射 List
类型的数据:
定义一个与列表中各元素的数据类型相同的数据库 TYPE模型对象
TYPE创建的类型包含OBJECT类
和TABLE类
,创建TABLE
类型要依赖
于OBJECT
类型,即:AS TABLE OF
后面接 OBJECT
类型
定义object类型:
CREATE OR REPLACE TYPE PLAN_OBJECT AS OBJECT (
PLAN_NUM VARCHAR2(100), --计划号
START_DATE DATE, --开始日
END_DATE DATE, --结束日
COUNT_DAYS NUMBER, --统计天数
RATE NUMBER --利率
)
定义table类型:
CREATE OR REPLACE TYPE PLAN_TABLE AS TABLE OF PLAN_OBJECT
JAVA 代码
下述代码缺少环境不能运行,目的只是展示在Java类中调用Oracle中的存储过程方法时,如何传入 List 类型的参数,
请勿照本宣科
;
package com.summer.test;
import oracle.sql.ARRAY;
import oracle.sql.ArrayDescriptor;
import oracle.sql.STRUCT;
import oracle.sql.StructDescriptor;
import java.io.Serializable;
import java.sql.*;
import java.util.logging.Logger;
public class ServicePlan implements Serializable {
private static final Logger log = Logger.getLogger(ServicePlan.class.getName());
Connection conn = null;//数据库链接
CallableStatement cs = null;//调用已储存过程方法的对象
String reCode = "";//返回编码
String reMsg = "";//返回信息
/*
* serNum:流水号
* entityPlanList:EntityPlanList 类型的实体类计划列表,里面有[计划号、开始日、结束日、统计天数、利率]5个属性字段
* origNum:原单据号
*
* */
public void callProcedure(String serNum, List<EntityPlanList> entityPlanList, String origNum) {
try {
// java.lang.ClassCastException:org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
// 原因:因为在使用连接池的情况下,Connection对象不是在BasicDataSource中实例化,而是在PoolingDataSource中被覆盖,被包装成PoolGuardConnectionWrapper内部类,
// 需使用Connection.getMetaData().getConnection()方法从PoolGuardConnectionWrapper获取原始连接。将传入的Connection强制转换为oracle.jdbc.OracleConnection
StructDescriptor structDescriptor = new StructDescriptor("PLAN_OBJECT", conn.getMetaData().getConnection());
//将数组类型的数据转换为Oracle type 传入存储过程
STRUCT[] structs = new STRUCT[entityPlanList.size()];
for (int i = 0; i < entityPlanList.size(); i++) {
EntityPlanList entityPlan = entityPlanList.get(i);
Object[] objects = new Object[5];
//util.Date 转换为 sql.Date (如果是sql.Date,无需转换了)
Date startDate = formatDate(entityPlan.getStartDate());//开始日
Date endDate = formatDate(entityPlan.getEndDate());//结束日
objects[0] = entityPlan.getPlanNum();//计划号
objects[1] = startDate;//开始日
objects[2] = endDate;//结束日
objects[3] = entityPlan.getCountDays();//统计天数
objects[4] = entityPlan.getRate();//利率
structs[i] = new STRUCT(structDescriptor, conn.getMetaData().getConnection(), objects);
}
ArrayDescriptor arrayDescriptor = ArrayDescriptor.createDescriptor("PLAN_TABLE ", conn.getMetaData().getConnection());
ARRAY arrPlan = new ARRAY(arrayDescriptor, conn.getMetaData().getConnection(), structs);
cs = conn.prepareCall("call PRO_PLAN(?,?,?,?,?)");
//存储过程入参和出参
cs.setString(1, serNum);//流水号
cs.setString(2, arrPlan);//计划列表
cs.setString(3, origNum);//原单据号
cs.registerOutParameter(4, Types.VARCHAR);//返回编码
cs.registerOutParameter(5, Types.VARCHAR);//返回信息
cs.execute();
reCode = cs.getString(4);//返回编码
reMsg = cs.getString(5);//返回信息
log.info("存储过程执行结果,编码: " + reCode + " 信息: " + reMsg);
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (cs != null) {
cs.close();
}
}
}
//Date转换
public static java.sql.Date formatDate(Date date) {
if (date == null) {
return null;
}
return new java.sql.Date(date.getTime());
}
}
链接转换可能出现的错误
标签:Java,--,List,Date,cs,Connection,PLAN,sql,Oracle From: https://blog.csdn.net/weixin_44666786/article/details/140477291因为用的是Oracle数据库,所以直接使用 Connection 会失败,必须转化为 OracleConnection ,否则会报如下异常:
java.lang.ClassCastException:org.apache.commons.dbcp.PoolingDataSource$PoolGuardConnectionWrapper cannot be cast to oracle.jdbc.OracleConnection
原因:
因为在使用连接池的情况下,Connection对象不是在BasicDataSource
中实例化,而是在PoolingDataSource
中被覆盖,被包装成PoolGuardConnectionWrapper内部类
,需使用Connection.getMetaData().getConnection()
方法从PoolGuardConnectionWrapper获取原始连接。将传入的Connection强制转换为
oracle.jdbc.OracleConnection`