BeanPropertyRowMapper
什么是 BeanPropertyRowMapper
BeanPropertyRowMapper<>(entityClass) 是 Spring 框架中用于将数据库查询结果映射到 Java 实体类的工具类,极大简化了数据库结果集到实体类的映射过程。
工作原理
- 通过反射获取实体类(entityClass)的属性信息
- 将查询结果集中的列名与实体类的属性名进行匹配(默认采用驼峰命名匹配规则)
- 自动将列值转换为对应属性的类型并设置到实体对象中
使用示例
// 查询用户并映射到User实体类
String sql = "SELECT id, username, email FROM users WHERE id = ?";
User user = jdbcTemplate.queryForObject(sql,new Object[]{1},new BeanPropertyRowMapper<>(User.class)
);
注意事项
- 实体类需要有默认构造函数
- 实体类属性名与数据库列名最好保持一致(或符合驼峰转换规则)
- 支持基本数据类型及其包装类的自动转换
- 对于复杂类型转换,可能需要自定义 RowMapper
继承关系
BeanPropertyRowMapper 位于 Spring 的 org.springframework.jdbc.core 包下:
- 直接父类:Object
- 实现的接口:RowMapper<T>(核心接口)
核心接口:RowMapper<T>
RowMapper<T> 是 Spring 定义的一个函数式接口,作用是将数据库查询结果的一行数据(ResultSet)映射为一个 Java 对象(T 类型)。
它只有一个抽象方法:
T mapRow(ResultSet rs, int rowNum) throws SQLException;
- 参数 rs:数据库查询返回的结果集(包含当前行的数据)
- 参数 rowNum:当前行的索引(从 0 开始)
- 返回值:映射后的 Java 对象
BeanPropertyRowMapper 与 RowMapper 的关系
- RowMapper 是「规则定义」:规定了 "如何把一行数据转成对象"
- BeanPropertyRowMapper 是「规则实现」:按照 "属性名匹配列名" 的规则具体实现了映射
其他 RowMapper 实现类
RowMapper 接口有很多其他实现类,用于不同场景:
- SingleColumnRowMapper:只映射结果集中的某一列(例如查询单个字段时使用)
- ColumnMapRowMapper:将一行数据映射为 Map<String, Object>(键是列名,值是字段值)
- 自定义 RowMapper:当默认映射规则不满足时,可自行实现 RowMapper 接口
入门建议
- 先理解 RowMapper 接口的作用:将一行数据库记录转换为 Java 对象
- 掌握 BeanPropertyRowMapper 的基本用法,注意实体类的要求
- 熟悉其自动映射规则,了解驼峰命名转换
- 当默认映射不满足需求时,学习如何实现自定义 RowMapper
总结
- 核心接口是 RowMapper<T>,作用是 "一行数据转对象"
- BeanPropertyRowMapper 是其常用实现,自动完成映射
- 简化了数据库结果集到实体类的转换代码
重写MapRow方法
@Override
public T mapRow(ResultSet rs, int rowNumber) throws SQLException {// 1. 状态检查与目标对象实例化Assert.state(this.mappedClass != null, "Mapped class was not specified");T mappedObject = BeanUtils.instantiate(this.mappedClass); // 通过默认构造函数创建新实例// 2. 创建BeanWrapper并初始化BeanWrapper bw = PropertyAccessorFactory.forBeanPropertyAccess(mappedObject);initBeanWrapper(bw); // 空方法,供子类扩展// 3. 获取结果集元数据ResultSetMetaData rsmd = rs.getMetaData();int columnCount = rsmd.getColumnCount();// 4. 严格模式校验的初始化(如果需要)Set<String> populatedProperties = (isCheckFullyPopulated() ? new HashSet<String>() : null);// 5. 遍历结果集的每一列for (int index = 1; index <= columnCount; index++) {// 5.1 获取列名并进行标准化处理(如转为小写、去除空格)String column = JdbcUtils.lookupColumnName(rsmd, index);String lowerCaseColumn = column.toLowerCase().replace(" ", ""); // 简化处理,实际可能更复杂// 5.2 从预先构建的缓存映射(mappedFields)中查找对应的属性描述符(PropertyDescriptor)PropertyDescriptor pd = this.mappedFields.get(lowerCaseColumn);if (pd != null) { // 如果找到匹配的属性try {// 5.3 根据属性类型从ResultSet中获取列值Object value = getColumnValue(rs, index, pd);// 5.4 通过BeanWrapper将值设置到目标对象的属性中bw.setPropertyValue(pd.getName(), value);// 5.5 如果启用了严格模式,记录已填充的属性if (populatedProperties != null) {populatedProperties.add(pd.getName());}} catch (NotWritablePropertyException ex) {// 处理无法写入属性的异常throw new DataRetrievalFailureException("Unable to map column " + column + " to property " + pd.getName(), ex);} catch (TypeMismatchException ex) {// 处理类型不匹配异常,例如NULL值映射到基本类型if (value == null && this.primitivesDefaultedForNullValue) {// 如果配置为基本类型使用默认值,则忽略异常logger.debug("Intercepted TypeMismatchException for row " + rowNumber + " and column '" + column + "' with value " + value + " when setting property '" + pd.getName() + "' of type " + pd.getPropertyType() + " on object: " + mappedObject);} else {throw ex; // 否则重新抛出异常}}}}// 6. 严格模式最终校验:确保所有需要映射的属性都从结果集中获取到了值if (populatedProperties != null && !populatedProperties.equals(this.mappedProperties)) {throw new InvalidDataAccessApiUsageException("Given ResultSet does not contain all fields " +"necessary to populate object of class [" + this.mappedClass + "]: " +this.mappedProperties);}// 7. 返回填充好的对象return mappedObject;
}
queryForObject
JdbcTemplate
的 queryForObject
方法的参数列表中,用于接收 SQL 参数的位置明确要求是 Object[]
类型。
public <T> T queryForObject(String sql, RowMapper<T> rowMapperObject[] args,)
这里的 args
参数类型固定为 Object[]
,所以必须传入一个 Object
数组
JdbcTemplate
的 queryForObject
方法有一个重载版本是这样定义的:
public <T> T queryForObject(String sql,RowMapper<T> rowMapper, Object... args)
这里的 Object... args
就是可变参数,它的语法允许你:
- 传递任意数量的参数(0 个、1 个、多个)
- 这些参数会被自动包装成一个
Object[]
数组 - 在方法内部,
args
其实就是一个Object[]
数组