当前位置: 首页 > news >正文

BeanPropertyRowMapper

什么是 BeanPropertyRowMapper

BeanPropertyRowMapper<>(entityClass) 是 Spring 框架中用于将数据库查询结果映射到 Java 实体类的工具类,极大简化了数据库结果集到实体类的映射过程。

工作原理

  1. 通过反射获取实体类(entityClass)的属性信息
  2. 将查询结果集中的列名与实体类的属性名进行匹配(默认采用驼峰命名匹配规则)
  3. 自动将列值转换为对应属性的类型并设置到实体对象中

使用示例

// 查询用户并映射到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 接口

入门建议

  1. 先理解 RowMapper 接口的作用:将一行数据库记录转换为 Java 对象
  2. 掌握 BeanPropertyRowMapper 的基本用法,注意实体类的要求
  3. 熟悉其自动映射规则,了解驼峰命名转换
  4. 当默认映射不满足需求时,学习如何实现自定义 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 就是可变参数,它的语法允许你:

    1. 传递任意数量的参数(0 个、1 个、多个)
    2. 这些参数会被自动包装成一个 Object[] 数组
    3. 在方法内部,args 其实就是一个 Object[] 数组
    http://www.dtcms.com/a/395713.html

    相关文章:

  • 深入解析Java中String的不可变性
  • windows-安装kafka并启动
  • linux 驱动私有数据
  • 信息系统监理师软考备考指南:组织协调与沟通管理专题精讲
  • 【开题答辩全过程】以 JAVA农产品销售系统为例,包含答辩的问题和答案
  • Python 网络爬虫生态全景综述
  • MCP— Model Context Protocol(模型上下文协议)
  • 解决ubuntu无法连接上security.ubuntu.com:80 (185.125.190.81)的问题
  • SHAP分析 | MATLAB实现XGBoost极限梯度提升树多输入单输出回归预测+SHAP可解释分析分析(预测新数据,多指标评价)
  • 磁共振成像原理(理论)11:梯度回波 (Gradient Echoes)
  • odoo18全局菜单搜索
  • langchain链中的高级组件
  • 鸿蒙:使用animation或animateTo实现图片无限旋转效果
  • 02)阿里 Arthas(阿尔萨斯)开源的 Java 诊断工具原理分析、JVM动态加载“代理程序“(Agent) 的机制、vm.loadAgent原理
  • [学习笔记][机器学习-周志华] 第1章 绪论
  • Node.js面试题及详细答案120题(111-120) -- 进阶与扩展篇
  • 鞋底布线前传:CAD三维建模如何实现精准凸起设计
  • 华为无线网络技术基础
  • Django 模型与 ORM 全解析(二):数据库操作
  • Python 2025:AI与自动化运维的融合新纪元
  • MySQL 核心函数与约束详解
  • 设计模式简要
  • 服务扩容与容量评估手册
  • Pyside6 + QML - 信号与槽08 - 一个函数被多个信号触发(带参数)
  • 【第十一章】Python 调用 MySQL 全面指南:从基础到实践​
  • 新手玩家如何使用云手机
  • 【Datawhale组队学习202509】AI硬件与机器人大模型 task02 视觉感知与手眼协调
  • 基础算法---【前缀和】
  • YOLO系统——yolov1工作原理
  • 第20讲 机器学习中的分类数据