Cyan Blog Cyan Blog
首页
  • Java (opens new window)
  • JUC (opens new window)
  • JVM (opens new window)
  • Redis

    • Redis安装 (opens new window)
    • Redis基础 (opens new window)
    • Redis实战 (opens new window)
    • Redis集群安装 (opens new window)
    • Redis分布式缓存 (opens new window)
    • Redis多级缓存 (opens new window)
    • Redis原理 (opens new window)
  • 管理工具

    • Maven (opens new window)
    • Git (opens new window)
  • SSM

    • Spring (opens new window)
    • SpringBoot (opens new window)
    • Mybatis (opens new window)
    • MybatisPlus (opens new window)
  • 微服务

    • Docker (opens new window)
    • RabbitMQ (opens new window)
    • SpringCloud (opens new window)
    • Dubbo (opens new window)
    • MongoDB (opens new window)
    • Zookeeper (opens new window)
  • Java面试题 (opens new window)
  • JUC面试题 (opens new window)
  • JVM面试题 (opens new window)
  • Linux面试题 (opens new window)
  • SQL面试题 (opens new window)
  • Maven面试题 (opens new window)
  • Redis面试题 (opens new window)
  • SSM面试题 (opens new window)
  • SpringCloud面试题 (opens new window)
  • Linux (opens new window)
  • C++ (opens new window)
  • 数据库

    • MySQL (opens new window)
    • NoSQL (opens new window)
  • 软件测试

    • 软件测试 (opens new window)
  • 加密解密 (opens new window)
  • bilibili字幕提取 (opens new window)
  • 道理 (opens new window)
  • 关于博主

    • Github (opens new window)
    • CSDN (opens new window)
  • 关于本站

    • 如何搭建博客网站 (opens new window)
首页
  • Java (opens new window)
  • JUC (opens new window)
  • JVM (opens new window)
  • Redis

    • Redis安装 (opens new window)
    • Redis基础 (opens new window)
    • Redis实战 (opens new window)
    • Redis集群安装 (opens new window)
    • Redis分布式缓存 (opens new window)
    • Redis多级缓存 (opens new window)
    • Redis原理 (opens new window)
  • 管理工具

    • Maven (opens new window)
    • Git (opens new window)
  • SSM

    • Spring (opens new window)
    • SpringBoot (opens new window)
    • Mybatis (opens new window)
    • MybatisPlus (opens new window)
  • 微服务

    • Docker (opens new window)
    • RabbitMQ (opens new window)
    • SpringCloud (opens new window)
    • Dubbo (opens new window)
    • MongoDB (opens new window)
    • Zookeeper (opens new window)
  • Java面试题 (opens new window)
  • JUC面试题 (opens new window)
  • JVM面试题 (opens new window)
  • Linux面试题 (opens new window)
  • SQL面试题 (opens new window)
  • Maven面试题 (opens new window)
  • Redis面试题 (opens new window)
  • SSM面试题 (opens new window)
  • SpringCloud面试题 (opens new window)
  • Linux (opens new window)
  • C++ (opens new window)
  • 数据库

    • MySQL (opens new window)
    • NoSQL (opens new window)
  • 软件测试

    • 软件测试 (opens new window)
  • 加密解密 (opens new window)
  • bilibili字幕提取 (opens new window)
  • 道理 (opens new window)
  • 关于博主

    • Github (opens new window)
    • CSDN (opens new window)
  • 关于本站

    • 如何搭建博客网站 (opens new window)
  • 简历项目
  • 面试

  • 场景题
  • Java面试题

  • 后端开发
  • 数据库面试题
  • Maven
  • MyBatis面试题
    • MyBatis执行流程?
    • Mybatis是否支持延迟加载?
    • 延迟加载的底层原理知道吗?
    • Mybatis的一级、二级缓存用过吗?
    • Mybatis的缓存
    • Mybatis的二级缓存什么时候会清理缓存中的数据?
    • MyBatis是如何进行分页的
  • Spring面试题
  • SpringBoot面试题
  • SpringCloud面试题

  • Redis面试题

  • 设计模式
  • 中间件

  • Other

  • Random

  • 面试
2025-03-12
1.9k
6.7m
目录
MyBatis执行流程?
Mybatis是否支持延迟加载?
延迟加载的底层原理知道吗?
Mybatis的一级、二级缓存用过吗?
Mybatis的缓存
Mybatis的二级缓存什么时候会清理缓存中的数据?
MyBatis是如何进行分页的

MyBatis面试题

多表查询的标签

association

collocation

# MyBatis执行流程?

MyBatis的执行流程如下:

  1. 读取MyBatis全局配置文件mybatis-config.xml和配置文件。
  2. 构造会话工厂SqlSessionFactory。
  3. 会话工厂创建SqlSession对象。
  4. 创建操作数据库的接口,Executor执行器。
  5. 获取Mapper代理对象
  6. Executor执行方法中的MappedStatement类型的参数。
  7. 输入参数映射,从Java类型->JDBC类型。
  8. 执行SQL
  9. 输出结果映射,从JDBC类型->Java类型。

# Mybatis是否支持延迟加载?

MyBatis支持延迟加载,即在需要用到数据时才加载。主要用于处理 关联数据,即那些不是主查询直接返回,而是通过额外 SQL 查询获取的数据。可以通过配置文件中的lazyLoadingEnabled配置启用或禁用延迟加载。

# 延迟加载的底层原理知道吗?

延迟加载的底层原理主要使用CGLIB动态代理实现:

  1. 当你查询数据时,Mybatis会使用CGLIB创建目标对象的代理对象,这个代理对象的关联属性(需要关联其他表的字段)是空的。
  2. 调用目标方法时,代理对象会拦截这个方法,如果发现查询的目标属性是null值,则先执行SQL查询。
  3. 获取数据后,设置属性值再继续执行目标方法。

# Mybatis的一级、二级缓存用过吗?

一级缓存:基于PerpetualCache的HashMap本地缓存,其存储作用域为Session,当Session进行flush或close之后,该Session中的所有Cache就将清空,默认打开一级缓存 二级缓存需要单独开启,作用域为Namespace或mapper,不是依赖于SQL session,默认也是采用PerpetualCache的HashMap存储。通过在核心配置文件和mapper映射文件配置来开启

# Mybatis的缓存

MyBatis设计了二级缓存机制来提升数据检索效率,减少数据库查询压力。

一级缓存是SqlSession级别的本地缓存,用于避免同一会话中重复查询相同数据,MyBatis会将查询结果缓存在SqlSession中,后续相同查询可直接从缓存读取。 而二级缓存是跨SqlSession的全局缓存。当任意SqlSession查询数据后,结果会存入二级缓存,其他查询可直接从中获取数据。

实现原理:

  • 一级缓存:每个SqlSession持有Executor,其中包含LocalCache对象。用户发起查询时先检查LocalCache,命中则直接返回,未命中才查库并写入缓存。所以一级缓存的生命周期随SqlSession,需注意:因为一级缓存,在分布式环境下可能引发脏读问题。

    image-20250519194006770
  • 二级缓存:通过CachingExecutor装饰器实现,在原Executor外增加缓存层。通过配置文件开启后,查询流程变为:二级缓存 → 一级缓存 → 数据库。它采用装饰器模式,在原有执行逻辑上添加缓存功能。

    image-20250519194407650
  1. 实现SqlSession间数据共享
  2. 缓存粒度可控制到namespace级别
  3. 通过Cache接口支持多种缓存实现(如Ehcache、Redis等)
  4. 提供更高的灵活性和可控性
image-20250519193955069

# Mybatis的二级缓存什么时候会清理缓存中的数据?

当作用域(一级缓存Session/二级缓存Namespaces)进行了新增、修改、删除操作后,默认该作用域下所有select中的缓存将被清空。

# MyBatis是如何进行分页的

分页是开发中的基础功能,MyBatis支持的分页方式可分为两大类:

  1. 逻辑分页(内存分页)先查询所有符合条件的数据到内存中,再通过代码筛选出分页数据。
    • 使用MyBatis的RowBounds对象,一次性加载,所有符合查询条件的目标数据在内存里,通过设置offset和limit参数实现内存分页。 在数据量比较大的情况下,JDBC驱动会做一些优化,不会把所有的结果,一次性存储在result set里面,而是先只加载一部分数据,然后再根据需求去数据库里面滚动,去加载对应后续的数据,这种方式不适合数据量较大的一个场景,而且有可能会频繁的访问数据库,造成比较大的压力,
  2. 物理分页(数据库分页),直接通过数据库的分页语法(如MySQL的LIMIT)实现。
    • 在Mapper XML中直接编写带分页参数的SQL(如LIMIT #{offset}, #{pageSize}),灵活性高但需重复编码。
    • interceptor拦截器 拦截器是MyBatis里提供了一种针对于不同生命周期的拦截器,比如拦截执行器方法,拦截参数的处理,拦截结果集的处理,拦截SQL语法构建的处理, 我们可以通过拦截需要分页的select语句,然后在这个select语句里面去动态拼接分页的关键字,从而去实现分页查询,这种方式的好处,统一处理分页逻辑,避免重复代码。 PageHelper、MyBatis-Plus等均基于此实现。

总结:

  • 直接在Select语句上增加数据库提供的分页关键字,让后在应用程序里面传递当前页以及每页展示的条数
  • 使用MyBatis提供的RowBounds对象,实现内存级别的分页,可以执行查询后的结果集进行截取,但是这种方法不适合大数据集,因为它会加载所有符合条件的数据到内存中在进行截取,不过JDBC会进行一些优化,不会一次性加载所有数据,会加载一部分数据,再根据需要滚动加载其他数据
  • 基于MyBatis里面的Interceptor拦截器,在Select语句只需之前动态的拼接分页关键字,一些第三方插件就是使用的这种方法,如PageHelper
  • 可以优先使用数据库层面的分页,在一些复杂分页场景考虑使用PageHelper这样的插件

# MyBatis里#{}和${}的区别是什么

MyBatis提供了#{}和${}两种占位符来实现动态SQL,在执行操作之前,MyBatis会对这两个占位符进行动态的解析,

  • #{} 会被MyBatis替换为PreparedStatement预编译SQL语句中的问号占位符(?),然后将参数传递给PreparedStatement对象,而且会对特殊字符进行转义。这种方式可以有效防止SQL注入攻击。MyBatis还会根据传入参数的类型自动转换成相应的数据库类型

  • 而${} 是直接将传入的参数值拼接到SQL语句中,MyBatis不会对它进行任何特殊处理。这意味着它不具备任何防护措施来阻止SQL注入攻击。通常用于无法使用预编译SQL的占位符,如动态表名、列名等非用户输入的场景。

所以#{}和${}最大的区别在于,前者是动态参数,后者是占位符,在实际应用里面呢,尽可能的应该去使用#{}占位符

#面试
上次更新: 2025/6/10 17:21:17
Maven
Spring面试题

← Maven Spring面试题→

最近更新
01
md
06-29
02
Redis
06-29
03
HBase
06-29
更多文章>
Theme by Vdoing | Copyright © 2025-2025 Cyan Blog
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式