Mybatis延迟加载详解

一、通过select语句实现延迟加载

在Mybatis中,延迟加载可以使用select语句来实现。假设我们有两个表,一个是用户表,一个是订单表,用户表中保存了用户的基本信息,订单表中保存了用户的订单信息。这两个表之间是一对多关系,即一个用户可以拥有多个订单。

在使用Mybatis查询一条用户记录时,如果需要同时查询该用户的所有订单信息,需要在Mapper文件中定义如下的select语句:

<select id="getUserWithOrders" resultMap="userMap">
  select * from user where id = #{userId}
  select * from order where user_id = #{userId}
</select>

这样的查询会产生一个问题:在查询用户信息时,同时也会查询该用户的所有订单信息,如果该用户拥有数千条订单信息,那么查询的效率就会非常低。此时,可以通过使用Mybatis的延迟加载来解决这个问题。

二、Mybatis延迟加载是什么

Mybatis中的延迟加载,指的是当我们查询一条记录时,并不会立即查询该记录的关联记录,而是当我们需要访问该关联记录时,才会进行查询。这种方式可以有效提高查询效率。

三、Mybatis延迟加载的原理面试题

Mybatis的延迟加载原理是什么?

在Mybatis中,延迟加载是通过动态代理实现的。当我们调用一个延迟加载的关联对象时,Mybatis会首先判断该对象是否为空,如果为空,则调用Mapper接口中的方法,查询该关联对象。在查询完成后,将查询结果封装到代理对象中,并返回该代理对象。

四、Mybatis延迟加载默认

Mybatis的延迟加载默认是关闭的。如果需要启用延迟加载,则需要在配置文件中开启相应的延迟加载项。

五、Mybatis延迟加载的实现方式

Mybatis中的延迟加载,有两种实现方式:

1. 延迟加载关联对象

延迟加载关联对象,指的是只有在需要访问关联对象时,才会进行查询。这种方式可以避免一次性查询大量数据,提高查询效率。

2. 延迟加载属性

延迟加载属性,指的是只有在需要访问属性时,才会进行查询。这种方式可以避免查询出大量无用的数据,提高查询效率。

六、Mybatis延迟加载的原理

Mybatis中的延迟加载,通过动态代理的方式实现。在查询时,如果需要延迟加载某个关联对象或属性,Mybatis会将该对象或属性封装到一个代理对象中,并返回该代理对象。

当我们访问代理对象时,Mybatis会先判断代理对象中是否已经加载了该关联对象或属性,如果没有加载,则调用Mapper接口中的方法,查询该关联对象或属性。在查询完成后,将查询结果封装到代理对象中,并返回该代理对象。下次访问该关联对象或属性时,直接返回代理对象中的值,不再进行查询。

七、Mybatis延迟加载怎么配置

Mybatis中的延迟加载需要在配置文件中进行配置。可以通过在Mapper文件中使用select标签,并指定fetchType属性的方式,来开启延迟加载。

例如,在查询用户信息时,我们可以通过以下方式开启延迟加载:

<resultMap id="userMap" type="user">
  <result property="id" column="id"/>
  <result property="name" column="name"/>
  <result property="orders" column="id" select="getOrdersByUserId" fetchType="lazy"/>
</resultMap>

<select id="getUserById" resultMap="userMap">
  select * from user where id = #{id}
</select>

<select id="getOrdersByUserId" resultMap="orderMap">
  select * from order where user_id = #{id}
</select>

在上面的代码中,我们使用了resultMap来定义查询结果的映射关系。其中,fetchType属性指定了关联对象的延迟加载方式。lazy表示延迟加载,即只有在需要访问该关联对象时,才会进行查询。

八、Mybatis延迟加载没反应

如果在使用Mybatis的延迟加载时,发现没有生效,可能是由于以下几个原因:

1. 配置文件中未开启延迟加载

在使用延迟加载时,需要在配置文件中开启相应的延迟加载项。如果未开启,延迟加载是不会生效的。

2. 关联对象已经被加载

如果一个关联对象已经被加载过了,则再次访问该对象时,不会触发延迟加载。在这种情况下,可以考虑使用二级缓存。

3. 关联对象不存在

如果一个关联对象不存在,则再次访问该对象时,也不会触发延迟加载。在这种情况下,需要检查关联对象的外键值是否正确。

九、Mybatis二级缓存

Mybatis中的二级缓存,是用来缓存Mapper文件中的查询结果的。在需要查询相同结果集时,如果已经存在于缓存中,就可以直接从缓存中获取结果,而不需要再次进行查询。这样可以有效提高查询效率。

在使用Mybatis的延迟加载时,可以使用二级缓存来避免多次查询同一条记录的关联对象。当一个关联对象已经被加载过了,可以将该对象缓存到二级缓存中。在下次访问该关联对象时,就可以直接从缓存中获取,而不再进行查询。

在Mybatis中,可以通过在配置文件中开启二级缓存和指定缓存类型来开启二级缓存。例如:

<settings>
  <setting name="cacheEnabled" value="true"/>
</settings>

<cache type="org.mybatis.caches.ehcache.EhcacheCache"/>

在上面的代码中,我们开启了二级缓存,并指定了缓存类型为Ehcache。如果需要使用其他类型的缓存,可以在type属性中指定相应的缓存类型。

十、Mybatis延迟加载附源码

以下是使用Mybatis实现延迟加载的源码:

public interface UserMapper {
  User getUserWithOrders(long userId);
}

// Mapper文件中的查询语句
<select id="getUserWithOrders" resultMap="userMap">
  select * from user where id = #{userId}
  select * from order where user_id = #{userId}
</select>

public class UserMapperImpl implements UserMapper {
  private final SqlSession sqlSession;
  private final OrderMapper orderMapper;

  public UserMapperImpl(SqlSession sqlSession, OrderMapper orderMapper) {
    this.sqlSession = sqlSession;
    this.orderMapper = orderMapper;
  }

  @Override
  public User getUserWithOrders(long userId) {
    User user = sqlSession.selectOne("getUserById", userId);
    user.setOrders(() -> orderMapper.getOrdersByUserId(userId));
    return user;
  }
}

public interface OrderMapper {
  List<Order> getOrdersByUserId(long userId);
}

// Mapper文件中的查询语句
<select id="getOrdersByUserId" resultMap="orderMap">
  select * from order where user_id = #{userId}
</select>

public class OrderMapperImpl implements OrderMapper {
  private final SqlSession sqlSession;

  public OrderMapperImpl(SqlSession sqlSession) {
    this.sqlSession = sqlSession;
  }

  @Override
  public List<Order> getOrdersByUserId(long userId) {
    return sqlSession.selectList("getOrdersByUserId", userId);
  }
}

public class User {
  private long id;
  private String name;
  private List<Order> orders;

  // getters and setters
}

public class Order {
  private long id;
  private long userId;
  private String content;

  // getters and setters
}

public interface LazyLoader<V> {
  V load();
}

public class LazyObject<T> implements Serializable {
  private static final long serialVersionUID = 1L;

  private final LazyLoader<T> loader;
  private T value;

  public LazyObject(LazyLoader<T> loader) {
    this.loader = loader;
  }

  public T getValue() {
    if (value == null) {
      value = loader.load();
    }
    return value;
  }
}

public class LazyList<T> extends ArrayList<T> implements Serializable {
  private static final long serialVersionUID = 1L;

  private final LazyLoader<List<T>> loader;

  public LazyList(LazyLoader<List<T>> loader) {
    this.loader = loader;
    add(null);
  }

  @Override
  public T get(int index) {
    T value = super.get(index);
    if (value == null) {
      List<T> list = loader.load();
      if (list != null && list.size() > index) {
        value = list.get(index);
        set(index, value);
      }
    }
    return value;
  }
}

原创文章,作者:小蓝,如若转载,请注明出处:https://www.506064.com/n/284509.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
小蓝小蓝
上一篇 2024-12-22 15:41
下一篇 2024-12-22 15:41

相关推荐

  • Java Bean加载过程

    Java Bean加载过程涉及到类加载器、反射机制和Java虚拟机的执行过程。在本文中,将从这三个方面详细阐述Java Bean加载的过程。 一、类加载器 类加载器是Java虚拟机…

    编程 2025-04-29
  • QML 动态加载实践

    探讨 QML 框架下动态加载实现的方法和技巧。 一、实现动态加载的方法 QML 支持从 JavaScript 中动态指定需要加载的 QML 组件,并放置到运行时指定的位置。这种技术…

    编程 2025-04-29
  • 理解Mybatis中的SQL Limit用法

    Mybatis是一种非常流行的ORM框架,提供了SQL映射配置文件,可以使用类似于传统SQL语言的方式编写SQL语句。其中,SQL的Limit语法是一个非常重要的知识点,能够实现分…

    编程 2025-04-29
  • 类加载的过程中,准备的工作

    类加载是Java中非常重要和复杂的一个过程。在类加载的过程中,准备阶段是其中一个非常重要的步骤。准备阶段是在类加载的连接阶段中的一个子阶段,它的主要任务是为类的静态变量分配内存,并…

    编程 2025-04-28
  • Lazarus LoadLibrary:DLL动态链接库的加载和使用

    本文将从以下几个方面介绍Lazarus中LoadLibrary和FreeLibrary函数的使用方法: 一、简介 LoadLibrary和FreeLibrary是Windows动态…

    编程 2025-04-27
  • Spring Boot本地类和Jar包类加载顺序深度剖析

    本文将从多个方面对Spring Boot本地类和Jar包类加载顺序做详细的阐述,并给出相应的代码示例。 一、类加载机制概述 在介绍Spring Boot本地类和Jar包类加载顺序之…

    编程 2025-04-27
  • 用Python加载鸢尾花数据

    本文将详细介绍如何使用Python加载鸢尾花数据,包括数据源的介绍、数据的获取和清洗、数据可视化等方面。 一、数据源的介绍 鸢尾花数据集(Iris dataset)是常用的分类实验…

    编程 2025-04-27
  • 神经网络代码详解

    神经网络作为一种人工智能技术,被广泛应用于语音识别、图像识别、自然语言处理等领域。而神经网络的模型编写,离不开代码。本文将从多个方面详细阐述神经网络模型编写的代码技术。 一、神经网…

    编程 2025-04-25
  • Linux sync详解

    一、sync概述 sync是Linux中一个非常重要的命令,它可以将文件系统缓存中的内容,强制写入磁盘中。在执行sync之前,所有的文件系统更新将不会立即写入磁盘,而是先缓存在内存…

    编程 2025-04-25
  • Python输入输出详解

    一、文件读写 Python中文件的读写操作是必不可少的基本技能之一。读写文件分别使用open()函数中的’r’和’w’参数,读取文件…

    编程 2025-04-25

发表回复

登录后才能评论