Mybatis---resultMap的延迟加载 (懒加载)

本文介绍MyBatis中懒加载的配置方法及实现细节,包括如何通过设置启用懒加载,以及在Mapper配置文件中如何定义懒加载的关联对象。

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

延迟加载

resultMap 的数据以 树状结构 为主,当我们用到分支数据的时候再查下,反之则,不查询,这样可以节省数据库资源。

在代码中可以更详细一些。

    <settings><!--  -->
        <!-- 懒加载设置为 true -->
        <setting name="lazyLoadingEnabled" value="true"/>
        <!-- 积极加载设置为false -->
        <setting name="aggressiveLazyLoading" value="false"/>
    </settings>

Mybatis的配置文件规定setting配置顺序得在properties节点下。
association 和collection 就具有懒加载特性
在Mapper配置文件中配置如下:

<mapper namespace="com.zll.mybatis.dao.OrderDaoLazy">
    <resultMap type="com.zll.mybatis.bean.Orders" id="findOrderDetailMap">
        <id column="id" property="id" />
        <result column="createTime" property="createTime" />
        <result column="userId" property="userId" />

        <association property="user" javaType="com.zll.mybatis.bean.User"
            column="id" select="findUser" />
        <collection property="orderItems" ofType="com.zll.mybatis.bean.OrderItem"
            column="id" select="findOrdersItem" />
    </resultMap>

    <select id="findOrderDetailLazy" resultMap="findOrderDetailMap">
        select * from orders
    </select>


    <select id="findUser" parameterType="int" resultType="com.zll.mybatis.bean.User">
        select *
        from user where id = #{id}
    </select>

    <select id="findOrdersItem" parameterType="int" resultType="com.zll.mybatis.bean.OrderItem">
        select * from orderItem where orderId = #{id}
    </select>
</mapper>

注意:由于是懒加载是分开查询,所以我们的每个select 映射也需要分开写。
这里需要注意的就是 association 和 collection 标签中的 column 和select属性
select: 填写 我们要调用的 select 映射的 id
column : 填写 我们要传递给 select 映射的 参数。

测试时只要输出list对象中的order的id。读取了User 和 OrderItem对象,出发了懒加载,所以你会看到控制台打印了3次 select 语句,当我们调用数据时才会查询数据库。

<think>好的,用户现在想了解MyBatis-Plus如何处理多表查询。首先,我需要回忆一下MyBatis-Plus的基本特性,它是一个增强工具,在MyBatis的基础上只做增强不做改变,简化开发。但多表查询一直是MyBatis的弱项,MyBatis-Plus在这方面并没有提供直接的封装,所以用户可能在使用时遇到了困惑,想知道有没有更好的方法。 用户之前的问题是关于Vue.js的表单验证和路由跳转,现在转向后端框架,可能是他们在实际项目中遇到了前后端交互的问题,特别是数据库查询部分。考虑到MyBatis-Plus主要用于单表操作,多表查询可能需要结合其他方式实现,用户可能希望了解如何高效地进行多表关联查询,同时保持代码的简洁。 接下来,我需要整理MyBatis-Plus处理多表查询的几种常见方法。首先是XML自定义SQL,这是最传统的方式,用户需要自己编写SQL语句,适合复杂的多表关联。然后是Wrapper自定义Join,虽然MyBatis-Plus官方没有直接支持,但可以通过自定义Wrapper来实现,不过这可能比较复杂,需要用户对MyBatis-Plus的底层有一定了解。 另外,还有注解方式,使用@Select等注解直接在Mapper接口上编写SQL,但这种方式对于复杂的多表查询可能不够灵活。关联查询映射也是一种方法,通过定义结果映射来处理多表查询结果,但需要手动配置resultMap。 用户可能更希望有代码示例,所以需要准备每种方法的示例代码,比如XML配置、Wrapper的使用、注解方式等。同时,用户可能关心这些方法的优缺点,比如灵活性、可维护性、性能等,需要进行分析比较。 此外,用户可能没有明确说出但潜在的需求是希望简化多表查询的操作,可能需要推荐一些第三方扩展,比如mybatis-plus-join,或者建议使用其他ORM框架如JPA,或者在架构上采用领域驱动设计,拆分服务,避免复杂查询。 还要注意提醒用户,MyBatis-Plus的核心优势在单表操作,多表查询需要结合原生MyBatis的功能,避免误导用户认为MyBatis-Plus可以完全替代复杂的SQL处理。同时,性能优化和索引的使用也是需要考虑的点,特别是在处理大数据量的多表查询时。 最后,总结各种方法的适用场景,帮助用户根据具体需求选择最合适的方案,并提供最佳实践建议,比如简单查询用XML,动态条件用Wrapper,复杂场景考虑其他方案等。确保回答结构清晰,步骤明确,让用户能够一步步理解和应用。</think>$\boxed{MyBatis-Plus多表查询解决方案详解}$ MyBatis-Plus主要聚焦单表操作,对于多表查询需结合原生MyBatis能力,以下是5种典型实现方式及对比: $\boxed{方法对比表}$ | 方法 | 适用场景 | 优点 | 缺点 | |--------------------|-------------------------|-------------------------|-------------------------| | XML自定义SQL | 复杂多表关联 | 灵活性强,支持复杂SQL | 需要手动编写SQL | | Wrapper扩展 | 动态条件关联查询 | 链式编程,条件构造方便 | 关联逻辑需自行实现 | | 注解方式 | 简单关联查询 | 代码简洁,无需XML | 复杂SQL可读性差 | | 结果集映射 | 嵌套对象结构 | 对象映射清晰 | 配置较复杂 | | 第三方扩展库 | 快速实现JPA风格关联 | 接近JPA体验 | 需引入额外依赖 | $\boxed{核心实现方案}$ $\textcolor{blue}{方案一:XML自定义SQL(推荐)}$ ```xml <!-- UserMapper.xml --> <select id="selectUserWithOrders" resultType="UserDTO"> SELECT u.*, o.order_no FROM user u LEFT JOIN order o ON u.id = o.user_id WHERE u.deleted = 0 </select> <!-- Mapper接口 --> public interface UserMapper extends BaseMapper<User> { List<UserDTO> selectUserWithOrders(); } ``` $\textcolor{green}{方案二:QueryWrapper扩展(动态条件)}$ ```java // 自定义Wrapper public class JoinWrapper<T> extends QueryWrapper<T> { public <R> JoinWrapper<T> join(String joinSql) { super.apply(joinSql); return this; } } // 使用示例 List<Map<String, Object>> list = new JoinWrapper<User>() .select("u.name, o.order_no") .join("LEFT JOIN order o ON u.id = o.user_id") .listMaps(); ``` $\textcolor{purple}{方案三:注解方式}$ ```java @Select("SELECT u.*, d.dept_name FROM user u " + "LEFT JOIN department d ON u.dept_id = d.id " + "WHERE u.id = #{userId}") @Results({ @Result(column = "dept_name", property = "deptName") }) UserDetailVO getUserWithDept(@Param("userId") Long userId); ``` $\boxed{结果集映射示例}$ ```java @Data public class UserOrderDTO { private Long id; private String userName; private List<Order> orders; // 嵌套集合 @Data public static class Order { private String orderNo; private BigDecimal amount; } } // XML映射配置 <resultMap id="userOrderMap" type="UserOrderDTO"> <id property="id" column="uid"/> <result property="userName" column="user_name"/> <collection property="orders" ofType="UserOrderDTO.Order"> <result property="orderNo" column="order_no"/> <result property="amount" column="amount"/> </collection> </resultMap> ``` $\boxed{性能优化建议}$ 1. **索引策略**: ```sql CREATE INDEX idx_user_dept ON user(dept_id); CREATE INDEX idx_order_user ON order(user_id); ``` 2. **分页优化**: ```java // 使用优化后的分页插件 @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL){ @Override protected void optimizeCount() { this.setOptimizeJoin(false); // 关闭连表优化 } }); return interceptor; } ``` 3. **延迟加载配置**: ```yml mybatis-plus: configuration: lazy-loading-enabled: true aggressive-lazy-loading: false ``` $\boxed{第三方扩展方案}$ 使用mybatis-plus-join插件: ```xml <dependency> <groupId>com.github.yulichang</groupId> <artifactId>mybatis-plus-join</artifactId> <version>1.4.6</version> </dependency> ``` ```java // 使用示例 List<UserDTO> list = JoinWrapper.create(User.class) .selectAll(User.class) .select(Order.class, Order::getOrderNo) .leftJoin(Order.class, Order::getUserId, User::getId) .list(UserDTO.class); ``` $\boxed{最佳实践建议}$ 1. **架构层面**: - 使用CQRS模式分离查询与命令操作 - 对复杂查询采用视图或存储过程 - 考虑引入Elasticsearch处理复杂搜索 2. **代码规范**: ```java // 推荐使用DO(Data Object)模式 @Data @TableName("user") public class UserDO { private Long id; private String name; private Long deptId; } // 查询专用DTO @Data public class UserDetailDTO { private String userName; private String deptName; private LocalDateTime createTime; } ``` 3. **事务管理**: ```java @Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.READ_COMMITTED, timeout = 30) public UserDetailVO getUserDetail(Long id) { // 多表操作 } ``` $\textcolor{red}{重要注意事项}$: 1. 避免N+1查询问题,优先使用JOIN代替多次查询 2. 分页查询时注意COUNT语句优化 3. 多表字段命名冲突使用`AS`别名 4. 超过3表关联时建议重构数据模型 5. 定期使用EXPLAIN分析SQL执行计划 $\boxed{诊断案例}$:性能低下查询优化 ```sql -- 原始SQL SELECT * FROM user u LEFT JOIN order o ON u.id = o.user_id LEFT JOIN product p ON o.product_id = p.id WHERE u.create_time > '2023-01-01' -- 优化方案 /* 1. 添加复合索引 */ CREATE INDEX idx_user_create ON user(create_time, id) /* 2. 使用覆盖索引 */ SELECT u.id, u.name, o.order_no, p.product_name ... ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值