Spring JDBC调用存储过程的几种情况

本文详细介绍了如何将Oracle存储过程与SpringJDBC进行集成,包括处理基本类型参数、自定义Struct类型参数及返回值。通过实例代码展示了如何设置存储过程参数、执行存储过程并获取返回的游标和Struct类型数据。同时,文章还讨论了如何处理自定义Struct类型的声明和使用,以及在执行存储过程时可能出现的字符集问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

注入spring jdbc,参见:http://godandghost.iteye.com/admin/blogs/1724763

1. 存储过程中各个出入参都是基本类型时:

PROCEDURE p_get_province
(
iv_code VARCHAR2, --字符串类型
in_staff_role NUMBER, --数字类型
in_provincial_id NUMBER,
iv_m_id VARCHAR2,
ocur_exec_status OUT pkg_ref_cursor.gcur_record_set, --游标类型
ocur_province OUT pkg_ref_cursor.gcur_record_set --游标类型
);



public static List getProvice(final Map<String, String> paramMap) throws Exception
{
try {
List list = template.execute(new ConnectionCallback<List>()
{
@Override
public List doInConnection(Connection conn)
throws SQLException, DataAccessException
{
CallableStatement call = conn.prepareCall("call p_get_province(?,?,?,?,?,?)");
call.setString("iv_code", paramMap.get("Report_Id"));
if (StringUtils.isNotBlank(paramMap.get("Role"))) {
call.setInt("in_staff_role", Integer.parseInt(paramMap.get("Role")));
} else {
call.setString("in_staff_role", null);
}
if (StringUtils.isNotBlank(paramMap.get("ProvinceId"))) {
call.setInt("in_provincial_id", Integer.parseInt(paramMap.get("ProvinceId")));
} else {
call.setString("in_provincial_id", null);
}
call.setString("iv_m_id", paramMap.get("mId"));
call.registerOutParameter("ocur_exec_status", OracleTypes.CURSOR);
call.registerOutParameter("ocur_province", OracleTypes.CURSOR);
DataSourceUtils.applyTimeout(call, template.getDataSource(), 30);// 30秒超时
call.execute();

ResultSet rs = (ResultSet) call.getObject("ocur_exec_status");
int status = 0;
String info = "";
while (rs.next()) {
status = rs.getInt("Exec_Status");
info = rs.getString("Exec_info");
}
rs.close();
if (status == 0) {
List<MyObject> provinceList = new ArrayList<MyObject>();
ResultSet rs1 = (ResultSet) call.getObject("ocur_province");
while (rs1.next()) {
MyObject mo = new MyObject();
mo.setValue(rs1.getString("province_value"));
mo.setText(rs1.getString("province"));
provinceList.add(mo);
}
rs1.close();
return provinceList;
} else {
return null;
}
}
});
return list;
}
catch (DataAccessException e) {
throw e;
}
catch (Exception e) {
throw e;
}
}


2.存储过程中有自定义struct时
Struct类型声明:

CREATE OR REPLACE TYPE header_struct as object
(
w_id varchar2(8),
a_time date,
b_time date,
token varchar2(20)
)

create or replace type Report_List as varray(2000) of REPORT_STRUCT

create or replace type REPORT_STRUCT as object(
REQUEST_ID NUMBER(10),
STATUS NUMBER(3),
FILENAME VARCHAR2(200),
DESCRIPTION VARCHAR2(201),
REQUESTDATETIME DATE
)

CREATE OR REPLACE TYPE ERROR_MESSAGE_STRUCT as object
(
error_type number(3),
error_code number(10),
message varchar2(255)
)

存储过程声明:

CREATE OR REPLACE PROCEDURE get_report_list
(
iv_header IN header_struct,
iv_function_name IN VARCHAR2,
iv_report_date IN DATE,
ov_report_list OUT report_list,
ov_error_message OUT error_message_struct
)

Java代码写法:

public static Object[] getReportResultList(final Header header,
final String functionName, final Date dateTime)
{
try {
return template.execute(new ConnectionCallback<Object[]>()
{
@Override
public Object[] doInConnection(Connection conn) throws SQLException, DataAccessException
{
Connection con = conn.getMetaData().getConnection();// 此处需要将connection类型转换一下
OracleCallableStatement call = (OracleCallableStatement) con
.prepareCall("call get_report_list(?,?,?,?,?)");

// 存储过程第一个参数
oracle.sql.STRUCT headerStruct = getHeaderStruct(header, con);
// 声明存储过程的入参
call.setSTRUCT(1, headerStruct);// 参数类型是Struct
call.setString(2, functionName);// 参数类型是String
call.setDate(3, dateTime);
// 声明存储过程的出参
call.registerOutParameter(4, OracleTypes.ARRAY, "REPORT_LIST");// REPORT_LIST必须大写
call.registerOutParameter(5, OracleTypes.STRUCT, "ERROR_MESSAGE_STRUCT");// ERROR_MESSAGE_STRUCT必须大写

DataSourceUtils.applyTimeout(call, sbcTemplate.getDataSource(), 30);
call.execute();

// 出参第一个结构体是一个Struct的Array
oracle.sql.ARRAY array = call.getARRAY(4);
List<ReportResult> resultList = new ArrayList<ReportResult>();
if (array != null) {
Datum[] data = array.getOracleArray();
for (Datum datum : data) {
STRUCT struct = (STRUCT) datum;
Datum[] datas = struct.getOracleAttributes();

int requestId = 0;
int status = 0;
String fileName = "";
String description = "";
NUMBER requestIdNum = (NUMBER) datas[0];
if (requestIdNum != null) {
requestId = requestIdNum.bigIntegerValue().intValue();
}
NUMBER statusNum = (NUMBER) datas[1];
if (statusNum != null) {
status = statusNum.bigIntegerValue().intValue();
}

try {
if (datas[2] != null) {
fileName = new String(datas[2].getBytes(), "GBK");
}
if (datas[3] != null) {
description = new String(datas[3].getBytes(), "GBK");
}
}
catch (UnsupportedEncodingException e) {
logger.warn("不支持的字符编码", e);
}
oracle.sql.DATE requestDate = (oracle.sql.DATE) datas[4];
java.sql.Timestamp date = null;
if (requestDate != null) {
date = requestDate.timestampValue();
}

ReportResult rr = new ReportResult(requestId,
status, fileName, description, date);
resultList.add(rr);
}
} else {
System.out.println("空");
}
// 第二个结构体errormessage
STRUCT errorMsgStruct = call.getSTRUCT(5);
ErrorMessage em = new ErrorMessage();
if (errorMsgStruct != null) {
em = initErrorMessage(errorMsgStruct);
}
con.close();
return new Object[] { resultList, em };
}
});
}
catch (Exception e) {
throw e;
}
}

private static STRUCT getHeaderStruct(Header header, Connection con)
throws SQLException
{
java.sql.Timestamp aTime = null;
java.sql.Timestamp bTime = null;
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
try {
java.util.Date aTimeUtil = sdf.parse(header.getaTime());
aTime = new java.sql.Timestamp(aTimeUtil.getTime());
}
catch (ParseException e) {
logger.note("aTime时间转换发生错误", e);
}
try {
java.util.Date bTimeUtil = sdf.parse(header.getbTime());
bTime = new java.sql.Timestamp(bTimeUtil.getTime());
}
catch (ParseException e) {
logger.note("bTime时间转换发生错误", e);
}

Object[] head = { header.getWitnessID(), bTime, aTime,
header.getToken() };
oracle.sql.StructDescriptor headerDesc = oracle.sql.StructDescriptor.createDescriptor("HEADER_STRUCT", con);// HEADER_STRUCT必须大写
oracle.sql.STRUCT headerStruct = new oracle.sql.STRUCT(headerDesc, con, head);
return headerStruct;
}

private static ErrorMessage initErrorMessage(STRUCT errorMsgStruct)
{
try {
Datum[] datas = errorMsgStruct.getOracleAttributes();

int errorType = 0;
int errorCode = 0;
String errorMsg = "";

NUMBER errorTypeNum = (NUMBER) datas[0];
if (errorTypeNum != null) {
errorType = errorTypeNum.bigIntegerValue().intValue();
}
NUMBER errorCodeNum = (NUMBER) datas[1];
if (errorCodeNum != null) {
errorCode = errorCodeNum.bigIntegerValue().intValue();
}
try {
if (datas[2] != null) {
errorMsg = new String(datas[2].getBytes(), "GBK");
}
}
catch (UnsupportedEncodingException e) {
logger.warn("不支持的字符编码", e);
}
ErrorMessage em = new ErrorMessage(errorCode, errorType, errorMsg);
return em;
}
catch (SQLException e) {
return null;
}
}


需要注意的是,oracle的驱动包与字符集包必须对应,否则一旦Struct结构体中有字符串(无论是不是中文)都是乱码,导致Struct结构体初始化失败。我用的oracle驱动包是ojdbc6.jar,就必须用与其对应的orai18n.jar。关于乱码问题可以参见:http://blog.youkuaiyun.com/hzw2312/article/details/8444462

另注:
当使用Connection con = conn.getMetaData().getConnection();转换数据库连接时,此连接相当于新建了一个连接,不受Spring JDBC控制,不会自动回收。所以在程序最后需要手动关闭:con.close();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值