Spring Boot调用含Table/TableType入参出参存储过程报错如何解决
该Cannot convert SQL type TABLE to Java type java.lang.Object报错的核心原因是Spring Data JPA/JDBC的默认类型转换器未适配数据库自定义的TABLE类型,无法直接完成SQL TABLE类型到Java对象的映射,可按以下步骤解决:
解决步骤
1. 定义与TABLE类型结构匹配的Java POJO
确保POJO字段的顺序、数据类型和数据库中定义的TABLE类型字段完全对应,示例如下:
// 对应数据库定义 TYPE user_table AS TABLE(id INT, name VARCHAR(20)) public class UserTableItem { private Integer id; private String name; // 全参构造方法 public UserTableItem(Integer id, String name) { this.id = id; this.name = name; } // getter、setter方法省略 }
2. 自定义TABLE类型的映射处理器
实现SqlReturnType接口完成出参的TABLE类型到JavaList<POJO>的转换,示例如下:
public class TableTypeReturnType implements SqlReturnType { @Override public Object getTypeValue(CallableStatement cs, int paramIndex, int sqlType, String typeName) throws SQLException { Array array = cs.getArray(paramIndex); Object[] structs = (Object[]) array.getArray(); List<UserTableItem> result = new ArrayList<>(); for (Object struct : structs) { Struct s = (Struct) struct; Object[] attrs = s.getAttributes(); // 按TABLE类型字段顺序取值映射到POJO result.add(new UserTableItem((Integer) attrs[0], (String) attrs[1])); } return result; } }
3. 手动配置存储过程调用参数
不要使用@Procedure注解的默认自动映射,改用SimpleJdbcCall手动指定TABLE类型参数的类型和处理器,示例如下:
@Autowired private JdbcTemplate jdbcTemplate; public List<UserTableItem> callProcedureWithTableType(List<UserTableItem> inputList) throws SQLException { // 初始化存储过程调用对象 SimpleJdbcCall jdbcCall = new SimpleJdbcCall(jdbcTemplate) .withProcedureName("你的存储过程名称") .declareParameters( // 声明入参:参数名、类型为ARRAY、对应数据库的TABLE类型名 new SqlParameter("in_table_param", Types.ARRAY, "USER_TABLE"), // 声明出参:参数名、类型为ARRAY、对应数据库的TABLE类型名、指定自定义处理器 new SqlOutParameter("out_table_param", Types.ARRAY, "USER_TABLE", new TableTypeReturnType()) ); // 构造入参TABLE对应的数据结构 Connection connection = jdbcTemplate.getDataSource().getConnection(); Object[] structArray = inputList.stream() .map(item -> { try { return connection.createStruct("USER_TABLE", new Object[]{item.getId(), item.getName()}); } catch (SQLException e) { throw new RuntimeException(e); } }) .toArray(); Array inputArray = connection.createArrayOf("USER_TABLE", structArray); // 执行调用获取返回结果 Map<String, Object> params = new HashMap<>(); params.put("in_table_param", inputArray); Map<String, Object> resultMap = jdbcCall.execute(params); List<UserTableItem> outputList = (List<UserTableItem>) resultMap.get("out_table_param"); // 关闭临时连接避免泄漏 connection.close(); return outputList; }
4. 适配不同数据库的特殊实现
- Oracle数据库的嵌套表/VARRAY类型,需替换示例中的
Array/Struct为Oracle驱动对应的ARRAY/STRUCT实现类 - PostgreSQL的复合类型数组,需使用驱动包中的
PGobject完成结构映射 - Hibernate 6+版本原生支持结构化用户自定义类型,可通过
@UserDefinedType注解简化配置,无需手动编写类型处理器
注意事项
- 数据库TABLE类型的字段顺序必须和POJO映射时的取值顺序完全一致,否则会出现类型转换异常或者数据错位
- 调用过程中手动获取的连接必须显式关闭,避免数据库连接池资源泄漏
内容的提问来源于stack exchange,提问作者LearnerOP
相关产品推荐
相关产品推荐

