使用Hibernate调用多输出类型存储过程:临时表映射Java输出值
如何在Java中调用Oracle存储过程并映射自定义表类型输出
你提供的Oracle存储过程属于package_name包,其中输出参数Ind是自定义的关联数组类型(pkg_Type,基于typ记录类型),下面是Java中调用并映射该输出的具体实现步骤:
1. 准备依赖
确保项目中引入适配Oracle版本的JDBC驱动(如ojdbc8或ojdbc11),驱动需要支持Oracle自定义类型的处理。
2. 定义对应Oracle记录类型的Java实体类
对应Oracle中typ记录类型,创建Java实体类来接收每条记录的数据:
public class TypRecord { private Integer id; private String name; public TypRecord() {} public TypRecord(Integer id, String name) { this.id = id; this.name = name; } // getter和setter方法 public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
3. 调用存储过程并处理输出参数
使用Oracle JDBC扩展API来处理自定义表类型,示例代码如下:
import oracle.jdbc.OracleConnection; import oracle.jdbc.OraclePreparedStatement; import oracle.sql.ARRAY; import oracle.sql.ArrayDescriptor; import oracle.sql.STRUCT; import oracle.sql.StructDescriptor; import java.sql.Connection; import java.sql.Date; import java.sql.DriverManager; import java.util.ArrayList; import java.util.List; public class ProcedureCaller { public static void main(String[] args) { String url = "jdbc:oracle:thin:@//your-oracle-host:port/service-name"; String user = "your-username"; String password = "your-password"; try (Connection conn = DriverManager.getConnection(url, user, password)) { // 转换为OracleConnection以使用扩展API OracleConnection oracleConn = conn.unwrap(OracleConnection.class); // 定义存储过程调用语句 String callSql = "{ call package_name.procedure_name(?, ?, ?, ?, ?) }"; OraclePreparedStatement pstmt = (OraclePreparedStatement) oracleConn.prepareCall(callSql); // 设置输入参数 pstmt.setLong(1, 123); // 对应Id参数 pstmt.setDate(2, Date.valueOf("2024-01-01")); // 对应sDate参数 pstmt.setDate(3, Date.valueOf("2024-01-31")); // 对应eDate参数 // 注册输出参数:指定自定义类型的完整名称(包名.类型名) pstmt.registerOutParameter(4, oracleConn.getType("PACKAGE_NAME.PKG_TYPE")); pstmt.registerOutParameter(5, java.sql.Types.VARCHAR); // 执行存储过程 pstmt.execute(); // 获取Sol输出参数 String sol = pstmt.getString(5); System.out.println("Sol输出值:" + sol); // 获取Ind输出参数(自定义表类型) ARRAY indArray = (ARRAY) pstmt.getArray(4); // 获取记录类型的描述器 StructDescriptor structDesc = StructDescriptor.createDescriptor("PACKAGE_NAME.TYP", oracleConn); // 将数组转换为STRUCT数组,再映射为Java实体类列表 Object[] structs = (Object[]) indArray.getArray(); List<TypRecord> recordList = new ArrayList<>(); for (Object obj : structs) { STRUCT struct = (STRUCT) obj; Object[] attrs = struct.getAttributes(); TypRecord record = new TypRecord((Integer) attrs[0], (String) attrs[1]); recordList.add(record); } // 处理结果列表 System.out.println("Ind输出的记录列表:"); for (TypRecord record : recordList) { System.out.printf("ID: %d, Name: %s%n", record.getId(), record.getName()); } // 关闭资源 pstmt.close(); } catch (Exception e) { e.printStackTrace(); } } }
关键注意事项
- 类型名称大小写:Oracle默认会将标识符转为大写,所以代码中使用
PACKAGE_NAME.PKG_TYPE而非小写的package_name.pkg_type,除非创建类型时用双引号指定了小写名称。 - 驱动兼容性:确保ojdbc驱动版本与Oracle数据库版本匹配,避免出现类型处理的兼容性问题。
- 关联数组处理:
INDEX BY BINARY_INTEGER的表类型属于Oracle关联数组,JDBC中通过ARRAY类型来接收,需要用StructDescriptor来解析每条记录的结构。
内容的提问来源于stack exchange,提问作者Just a coder
相关产品推荐
相关产品推荐

