首页 > 数据库 >Java中如何将一个 List 类型的参数传入存储过程(Oracle数据库)

Java中如何将一个 List 类型的参数传入存储过程(Oracle数据库)

时间:2024-07-18 11:26:25浏览次数:17  
标签:Java -- List Date cs Connection PLAN sql Oracle

Java中如何将一个 List 类型的参数传入存储过程(Oracle数据库)

步骤简述

  1. 定义好存储过程,Java中的数组对象
  2. 建立数据库映射对象来映射 List 类型的数据
  3. 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());
    }
}


链接转换可能出现的错误

因为用的是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`

标签:Java,--,List,Date,cs,Connection,PLAN,sql,Oracle
From: https://blog.csdn.net/weixin_44666786/article/details/140477291

相关文章