BeanPropertyRowMapper使用注意事项

BeanPropertyRowMapper是Spring提供的一个用于自动将数据库查询结果映射到Java Bean的工具。它依赖于属性名称与数据库列名的匹配,支持驼峰式和下划线分隔的转换。然而,对于不遵循规则的特殊字段,如ORDER_NUM2和ORDER_NUM_3,映射会失败并返回null。在源码中,initialize方法和underscoreName方法揭示了映射机制,强调了字段名必须能够转换为符合Java Bean规范的成员变量名称。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

query过程都可以进行数据类型自动转换,而且不仅仅按标准命名,还可以支持下划线分隔后拼接成驼峰式字符
完全轻量级.
BeanPropertyRowMapper/ParameterizedBeanPropertyRowMapper ,如果PO和数据库模型的字段完全对应(字段名字一样或者驼峰式与下划线式对应),如果使用JdbcTemplate则可以使用这个RowMapper作为PO和数据库的映射

Spring 2.5 提供了一个便利的RowMapper实现-----BeanPropertyRowMapper

它可自动将一行数据映射到指定类的实例中 它首先将这个类实例化,然后通过名称匹配的方式,映射到属性中去。

例如:属性名称(vehicleNo)匹配到同名列或带下划线的同名列(VEHICLE_NO)。

如果某个属性不匹配则返回属性值为Null;

//用BeanPropertyRowMapper自动匹配

new BeanPropertyRowMapper(User.class)


SpringJDBC BeanPropertyRowMapper  查询的时候 一般的数据库字段都可以正常映射到 bean!
  字段          bean属性
USER_NAME --> userName
USER_ID   --> userId

但是碰到一些特殊的(暂不考虑命名是否合理)这就映射不上了!
比如:
ORDER_NUM2   --> OrderNum2 (should be orderNum2)
ORDER_NUM_3     

<think>好的,用户之前询问了如何在Spring Boot中使用JPA实现子表反查父表的数据展示,现在他要求不使用JPA。我需要考虑用户可能的背景和需求。用户可能对JPA不够熟悉,或者项目中有其他持久层框架的限制,比如使用MyBatis或者纯JDBC。也可能用户希望更直接地控制SQL查询,避免ORM框架带来的复杂性。 首先,我需要回顾之前的回答,确保新的方法不使用JPA,但保持功能相同。用户需要实体类、DTO、Repository、Service和Controller的示例,但这次不使用JPA的注解和接口。所以需要替换为基于JDBC或者MyBatis的实现方式。 考虑到用户可能更倾向于使用Spring的JdbcTemplate,因为它在Spring Boot中集成方便,无需复杂的配置。同时,使用JdbcTemplate可以展示更底层的SQL操作,适合用户希望直接控制查询的情况。 接下来,我需要设计实体类,去掉JPA的注解,改为普通的Java类。例如,Order和OrderItem类不再有@Entity、@Id等注解,而是简单的POJO。然后,Repository层需要手动处理数据库连接和查询,将结果集映射到实体对象。这里可以使用RowMapper或者BeanPropertyRowMapper来实现结果集到对象的映射。 在Service层,需要调用Repository的方法获取数据,并转换为DTO。Controller层保持不变,处理HTTP请求并返回响应。 需要注意的是,在查询子表时关联父表数据,需要编写JOIN查询的SQL语句,手动处理结果集中的父表字段,并将其设置到DTO中。例如,查询OrderItem时同时获取Order的相关字段,然后在RowMapper中将这些字段组合到DTO里。 另外,要处理数据库连接和事务管理,确保在Repository中使用JdbcTemplate的方法时,正确管理资源。可能还需要配置数据源,但用户可能已经了解这部分,所以示例中可以省略配置细节,专注于核心逻辑。 测试数据插入部分,需要手动编写插入SQL,使用JdbcTemplate的update方法执行。响应示例和注意事项也需要调整,比如提到使用JOIN避免N+1问题,手动映射字段,以及处理结果集的方法。 最后,需要对比之前的JPA实现,说明不同方法的优缺点,比如更灵活但需要更多手动编码,适合对SQL控制要求高的场景。确保用户理解两种方法的适用情况,以便根据项目需求选择合适的方式。</think>以下是基于Spring Boot **不使用JPA**(使用纯JDBC或MyBatis风格)实现子表反查父表的完整示例: --- ### 1. 实体类定义(无JPA注解) ```java // 父表 Order.java public class Order { private Long id; private String orderNumber; private LocalDateTime createTime; // getters/setters } // 子表 OrderItem.java public class OrderItem { private Long id; private String productName; private Integer quantity; private Long orderId; // 关联父表的外键 // getters/setters } ``` --- ### 2. DTO对象(带父表信息) ```java public class OrderItemWithOrderDTO { private Long itemId; private String productName; private Integer quantity; private String orderNumber; // 父表字段 private LocalDateTime orderTime; // 构造方法(通过SQL查询结果直接映射) public OrderItemWithOrderDTO(Long itemId, String productName, Integer quantity, String orderNumber, LocalDateTime orderTime) { // 字段赋值... } // getters } ``` --- ### 3. Repository实现(使用JdbcTemplate) ```java @Repository public class OrderItemRepository { private final JdbcTemplate jdbcTemplate; public OrderItemRepository(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } // 带JOIN的查询方法 public List<OrderItemWithOrderDTO> findItemsWithOrderInfo(String productName) { String sql = """ SELECT i.id AS item_id, i.product_name, i.quantity, o.order_number, o.create_time AS order_time FROM order_items i INNER JOIN orders o ON i.order_id = o.id WHERE i.product_name = ? """; return jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(OrderItemWithOrderDTO.class), productName); } } ``` --- ### 4. Service层 ```java @Service public class OrderService { private final OrderItemRepository orderItemRepository; public OrderService(OrderItemRepository orderItemRepository) { this.orderItemRepository = orderItemRepository; } public List<OrderItemWithOrderDTO> getItemsWithOrderInfo(String productName) { return orderItemRepository.findItemsWithOrderInfo(productName); } } ``` --- ### 5. 自定义RowMapper(复杂映射场景) ```java public class OrderItemMapper implements RowMapper<OrderItemWithOrderDTO> { @Override public OrderItemWithOrderDTO mapRow(ResultSet rs, int rowNum) throws SQLException { return new OrderItemWithOrderDTO( rs.getLong("item_id"), rs.getString("product_name"), rs.getInt("quantity"), rs.getString("order_number"), rs.getTimestamp("order_time").toLocalDateTime() ); } } // 在Repository中使用 public OrderItemWithOrderDTO findById(Long itemId) { String sql = "SELECT ... WHERE i.id = ?"; return jdbcTemplate.queryForObject(sql, new OrderItemMapper(), itemId); } ``` --- ### 6. 测试数据插入 ```java @SpringBootTest public class DataInitializer { @Autowired private JdbcTemplate jdbcTemplate; @Test void insertTestData() { jdbcTemplate.update("INSERT INTO orders(order_number, create_time) VALUES (?, ?)", "20230816-001", LocalDateTime.now()); Long orderId = jdbcTemplate.queryForObject("SELECT LAST_INSERT_ID()", Long.class); jdbcTemplate.update(""" INSERT INTO order_items(product_name, quantity, order_id) VALUES (?, ?, ?) """, "笔记本电脑", 1, orderId); } } ``` --- ### 响应示例(与JPA版本一致) ```json { "itemId": 1, "productName": "笔记本电脑", "quantity": 1, "orderNumber": "20230816-001", "orderTime": "2023-08-16T09:15:22" } ``` --- ### 关键点说明: 1. **SQL显式控制**:通过手写JOIN语句实现关联查询 2. **结果集映射**: - 简单场景使用`BeanPropertyRowMapper`(要求数据库字段名与Java属性名一致) - 复杂场景自定义`RowMapper` 3. **DTO直接构造**:通过SQL别名(如`AS order_time`)匹配构造函数参数 4. **性能优化**:单次SQL查询获取所有数据,避免N+1问题 --- ### 对比JPA方案的差异: | 特性 | JPA方案 | 非JPA方案 | |--------------------|--------------------------|-----------------------| | 关联关系管理 | 自动对象导航 | 手动JOIN查询 | | SQL控制 | 生成或JPQL | 完全手写 | | 结果映射 | 自动ORM映射 | 手动RowMapper/DTO构造 | | 事务管理 | 声明式事务 | 需要手动控制 | | 适合场景 | 快速开发简单CRUD | 需要复杂SQL优化的场景 | --- 如果需要更底层的实现(如纯JDBC),可以进一步封装`Connection`和`PreparedStatement`,但推荐使用`JdbcTemplate`保持代码简洁性。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值