Java JDBC如何从ResultSet结果集中提取List类型字段值
问题说明
执行数据库查询获取到ResultSet类型结果集后,需要将结果解析映射为Person类的对象列表,在提取List<Integer>类型的兄弟姐妹数量字段时,直接调用rs.getObject("siblings",ArrayList.class)强转执行失败。
原实现代码存在两处明显问题:
- 集合初始化泛型写错:
new ArrayList<Offer>()应修正为new ArrayList<Person>() - JDBC原生API不支持直接将数据库集合/数组字段映射为
ArrayList类型,直接强转会抛出类型转换异常
正确提取列表类型字段的方案
根据数据库字段的存储类型,分两种常见场景处理:
场景1:字段为SQL标准ARRAY数组类型(如PostgreSQL的int[]、Oracle的VARRAY等)
使用JDBC标准提供的java.sql.Array接口处理,步骤如下:
- 调用
ResultSet#getArray()获取SQL数组对应的Array对象 - 从
Array对象中取出Java原生类型数组 - 将原生数组转换为需要的
List<Integer> - 释放
Array对象占用的资源
修正后的完整代码示例:
import java.sql.Array; import java.sql.ResultSet; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; static List<Person> parsePeople(ResultSet rs) throws SQLException { List<Person> people = new ArrayList<Person>(); while(rs.next()) { people.add(parsePerson(rs)); } return people; } static Person parsePerson(ResultSet rs) throws SQLException { Person p= new Person(); p.setFirstName(rs.getString("firstName")); p.setLastName(rs.getString("lastName")); // 处理数组类型字段 Array siblingsArray = null; try { siblingsArray = rs.getArray("siblings"); if (siblingsArray != null) { Integer[] siblings = (Integer[]) siblingsArray.getArray(); List<Integer> numberOfSiblings = new ArrayList<>(Arrays.asList(siblings)); p.setNumberOfSiblings(numberOfSiblings); } } finally { // 释放Array资源避免连接泄漏 if (siblingsArray != null) { siblingsArray.free(); } } return p; } class Person{ String firstName; String lastName; List<Integer> numberOfSiblings; // 省略getter/setter方法 public void setFirstName(String firstName) {this.firstName = firstName;} public void setLastName(String lastName) {this.lastName = lastName;} public void setNumberOfSiblings(List<Integer> numberOfSiblings) {this.numberOfSiblings = numberOfSiblings;} }
场景2:字段为JSON类型存储的数组(如MySQL JSON类型、普通文本存JSON数组)
这类场景下JDBC驱动会直接把字段值返回为字符串类型,需要先取出字符串,再通过JSON序列化工具转换为List<Integer>,以Jackson为例的实现片段:
import com.fasterxml.jackson.core.type.TypeReference; import com.fasterxml.jackson.databind.ObjectMapper; import java.sql.ResultSet; import java.sql.SQLException; import java.util.List; // 初始化JSON工具类,一般作为全局静态常量复用 private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); static Person parsePerson(ResultSet rs) throws SQLException { Person p= new Person(); p.setFirstName(rs.getString("firstName")); p.setLastName(rs.getString("lastName")); String siblingsJson = rs.getString("siblings"); if (siblingsJson != null) { try { List<Integer> numberOfSiblings = OBJECT_MAPPER.readValue(siblingsJson, new TypeReference<List<Integer>>() {}); p.setNumberOfSiblings(numberOfSiblings); } catch (Exception e) { throw new SQLException("解析siblings字段失败", e); } } return p; }
注意事项
- 不要直接将
rs.getObject()返回的对象强转为ArrayList,不同数据库驱动对非基础类型字段的内部实现不同,直接强转必然存在类型兼容问题 - 使用
java.sql.Array后必须调用free()方法释放资源,否则会持续占用数据库连接内存,引发内存泄漏 - 如果使用MyBatis、Spring Data JPA等ORM框架,直接配置对应类型处理器即可自动完成集合类型字段映射,不需要手动处理ResultSet转换
内容的提问来源于stack exchange,提问作者RCB
相关产品推荐
相关产品推荐

