关于MyBatis的一些面试题

news/2024/10/24 21:41:24/

mybatis的执行流程

MyBatis 的执行流程主要包括 SQL 解析、参数绑定、执行查询/更新、结果映射等几个步骤。下面详细解释每个步骤的执行流程:

1. 加载配置文件和映射文件

  • 加载 MyBatis 配置文件:启动时,MyBatis 通过 SqlSessionFactoryBuilder 读取并解析核心配置文件(mybatis-config.xml)和映射文件(*.xml)。
  • 创建 SqlSessionFactory:通过解析配置文件,MyBatis 会构建 SqlSessionFactory 对象,该对象负责生成 SqlSession

2. 创建 SqlSession

  • 创建 SqlSession:通过 SqlSessionFactory 获取 SqlSession 对象。SqlSession 是 MyBatis 的核心接口之一,负责执行 SQL 语句、获取映射器、提交事务等。
  • 绑定 Mapper 接口SqlSession 会根据开发者定义的接口,创建与之对应的 Mapper 动态代理对象,负责处理 SQL 操作。

3. 执行 SQL 语句

  • 调用 Mapper 接口方法:当调用 Mapper 接口的方法时,MyBatis 会找到与接口方法对应的 SQL 语句(Mapper XML 文件或注解方式定义的 SQL)。
  • 动态生成 SQL 语句:根据方法传递的参数,MyBatis 会动态生成 SQL 语句(包括 #{} 或 ${} 占位符的替换)。
    • #{} 占位符:采用预编译方式,防止 SQL 注入。
    • ${} 占位符:直接替换为字符串,不会进行预编译。

4. 参数处理

  • ParameterHandler 参数处理器:MyBatis 内部使用 ParameterHandler 将传递的参数与 SQL 中的占位符进行绑定,并处理各种参数类型(如基本类型、JavaBean、Map、List等)。

5. SQL 执行

  • Executor 执行器:MyBatis 中的执行器(SimpleExecutorReuseExecutorBatchExecutor 等)负责执行 SQL 语句。执行器负责与数据库进行交互,并处理缓存等事务。
  • 二级缓存:在执行 SQL 之前,MyBatis 会先检查二级缓存,如果缓存中有结果,则直接返回缓存数据;否则继续查询数据库。

6. 映射结果

  • ResultSetHandler 结果集处理器:SQL 查询结果返回后,ResultSetHandler 会将查询结果集映射到 Java 对象。它会根据配置的映射规则(如 XML 文件中的 resultMap,或通过注解的方式)将结果映射成对象。
  • 类型转换:MyBatis 支持多种数据类型的转换,如将数据库中的字段映射为 JavaBean 中的属性。

7. 事务管理

  • 手动提交和自动提交:默认情况下,MyBatis 会自动提交事务;如果配置为手动提交,则需要调用 commit() 方法来提交事务。
  • 事务控制:MyBatis 通过 Transaction 接口管理事务,包括事务的提交、回滚等操作。

8. 关闭 SqlSession

  • 资源释放:在执行完操作后,必须关闭 SqlSession,以释放数据库连接资源。SqlSession 的生命周期由开发者管理,建议使用 try-finally 结构来确保关闭。

MyBatis 执行流程图(可视化)

graph TD;A[加载MyBatis配置文件] --> B[创建SqlSessionFactory];B --> C[获取SqlSession];C --> D[调用Mapper接口方法];D --> E[动态生成SQL];E --> F[参数绑定];F --> G[执行SQL];G --> H[检查二级缓存];H --> I[查询数据库];I --> J[映射查询结果];J --> K[返回结果到调用者];C --> L[提交或回滚事务];K --> M[关闭SqlSession];

总结

  • 核心对象SqlSessionFactorySqlSessionExecutor
  • 核心操作:参数绑定、执行 SQL、结果映射、事务管理。

MyBatis延迟加载使用以及原理

MyBatis 的延迟加载(Lazy Loading)是指当需要用到某些数据时,才执行对应的 SQL 语句去查询数据库。这种机制可以有效减少不必要的数据库查询,提高系统性能。

1. MyBatis 延迟加载的使用

延迟加载的应用场景通常出现在一对一一对多关系的查询中。例如,查询订单时,每个订单可能会包含多个商品,但你可能只想在需要查看商品时才加载它们,而不是每次查询订单都加载所有商品数据。

配置方式

在 MyBatis 的核心配置文件 mybatis-config.xml 中,可以通过以下配置来启用延迟加载功能:

<configuration><settings><!-- 开启延迟加载 --><setting name="lazyLoadingEnabled" value="true"/><!-- 代理所有属性,延迟加载时一次性加载所有 --><setting name="aggressiveLazyLoading" value="false"/></settings>
</configuration>
  • lazyLoadingEnabled:启用延迟加载。
  • aggressiveLazyLoading:如果设置为 false,则只会在访问某个懒加载属性时才加载该属性的数据;如果设置为 true,一旦访问一个延迟加载的属性,所有延迟加载的属性都会被加载。

示例:一对多关系(订单和商品)

假设你有一个 OrderProduct 的一对多关系,Order 中包含一个 List<Product>

SQL Mapper 映射:

<resultMap id="orderMap" type="com.example.Order"><id column="order_id" property="id"/><result column="order_name" property="name"/><!-- 多对一映射(延迟加载) --><collection property="products" ofType="com.example.Product"select="selectProductsByOrderId" lazy="true"/>
</resultMap><!-- 查询订单 -->
<select id="selectOrderById" resultMap="orderMap">SELECT * FROM orders WHERE order_id = #{id}
</select><!-- 查询订单的商品(延迟加载部分) -->
<select id="selectProductsByOrderId" resultType="com.example.Product">SELECT * FROM products WHERE order_id = #{id}
</select>

Java 类:

java">public class Order {private Integer id;private String name;// 一对多关系,商品列表private List<Product> products;// getter and setter
}public class Product {private Integer id;private String productName;private Double price;// getter and setter
}

2. MyBatis 延迟加载的原理

MyBatis 延迟加载的实现依赖于Java 的动态代理机制。在加载 Order 对象时,MyBatis 不会立刻查询 products 数据,而是为 products 属性创建一个代理对象(Proxy),这个代理对象会记录当前对象的状态和代理方法的调用。

延迟加载的步骤:
  1. 第一次查询: 当调用 selectOrderById 查询 Order 时,MyBatis 只会执行订单表的查询,将 products 属性用代理对象代替,但不会立即查询 products 表中的数据。

  2. 访问延迟加载属性: 当你调用 order.getProducts() 时,MyBatis 会通过代理对象检测到该属性被调用,从而触发第二次查询,执行 selectProductsByOrderId 语句查询商品数据。

  3. 加载数据: 查询结果被返回并填充到 products 列表中。

工作原理
  • MyBatis 通过使用 CGLIBJDK 动态代理,为延迟加载的属性生成代理对象。当延迟加载的属性被调用时,代理对象会执行一个回调,动态加载所需的数据。
  • 代理模式 是延迟加载的核心。Proxy 对象会在调用目标属性时检查属性的加载状态,未加载时会触发查询并加载数据。
延迟加载控制的要点
  • 延迟加载需要在事务中使用,因为需要在对象的生命周期内保持数据库会话的连接状态。
  • 只有在属性被真正调用时,才会触发延迟加载。
注意事项
  • 如果你在 MyBatis 配置文件中将 aggressiveLazyLoading 设置为 true,一旦加载了某个延迟属性,所有延迟属性都会加载。这个配置适合当你需要尽快获取所有关联对象时。

3. 延迟加载和立即加载的对比

  • 延迟加载:只有在需要用到相关数据时,才会查询数据库并加载,适合处理关系型数据或减少不必要的查询。
  • 立即加载:一次性查询出所有关联数据,适合那些频繁需要访问的关联对象,避免后续多次查询数据库。

4. 总结

  • 延迟加载在查询一对多、多对一时非常有用,可以避免不必要的数据库查询。
  • MyBatis 通过动态代理机制实现延迟加载,当你访问某个延迟加载的属性时,才会触发相应的 SQL 查询。
  • 通过 lazyLoadingEnabledaggressiveLazyLoading 配置项,可以控制 MyBatis 延迟加载的行为。

MyBatis一级二级缓存

在 MyBatis 中,缓存是为了减少数据库查询的次数,提升性能。MyBatis 提供了两级缓存机制:一级缓存二级缓存

1. 一级缓存

一级缓存是SqlSession 级别的缓存,它的作用范围仅限于同一个 SqlSession 对象。在同一个 SqlSession 中,多次查询同一个数据时,MyBatis 会将查询结果存储到缓存中,之后的相同查询就可以直接从缓存中获取结果,而不再执行 SQL 查询。

一级缓存的特点
  • 默认开启:不需要配置,它会自动在 SqlSession 中工作。
  • 作用范围:仅限于同一个 SqlSession,当 SqlSession 关闭后,一级缓存也会被清除。
  • 缓存机制:以 statement ID(SQL 语句的唯一标识)查询参数 作为缓存的 key,查询结果作为 value。
  • 失效条件
    • 如果执行了 INSERTUPDATEDELETE 操作,一级缓存会被清空,因为数据发生了变化。
    • 手动清除缓存,例如调用 sqlSession.clearCache() 方法。
    • SqlSession 关闭时,一级缓存也会失效。

一级缓存的示例

java">SqlSession sqlSession = sqlSessionFactory.openSession();
// 第一次查询
User user1 = sqlSession.selectOne("com.example.mapper.UserMapper.selectUser", 1);
System.out.println(user1); // 查询数据库并缓存结果// 第二次查询相同数据
User user2 = sqlSession.selectOne("com.example.mapper.UserMapper.selectUser", 1);
System.out.println(user2); // 从缓存中获取结果,不查询数据库

2. 二级缓存

二级缓存是Mapper 级别的缓存,它的作用范围是同一个 Mapper 映射文件,即相同的 Mapper 共享二级缓存。二级缓存是一个跨 SqlSession 的缓存,它允许不同的 SqlSession 共享缓存,提高数据查询的效率。

二级缓存的特点
  • 需要手动开启:二级缓存默认是关闭的,必须在 MyBatis 的配置文件或 Mapper 映射文件中进行配置才能使用。
  • 作用范围:整个 Mapper 级别,不同的 SqlSession 可以共享相同的缓存数据。
  • 缓存机制:与一级缓存类似,使用 statement ID查询参数 作为 key,查询结果作为 value 存入缓存中。
  • 失效条件
    • 执行 INSERTUPDATEDELETE 操作时,二级缓存会失效。
    • 手动清除缓存或配置的缓存清理策略。
    • 配置了缓存的过期时间,超时后缓存失效。
开启二级缓存的步骤
  1. 在核心配置文件中启用二级缓存

<configuration>c<settings><!-- 启用全局二级缓存 --><setting name="cacheEnabled" value="true"/></settings>
</configuration>

   2. 在 Mapper 映射文件中启用二级缓存: 在对应的 Mapper.xml 文件中,添加如下配置:

<cache/>

  3.使用 Serializable 接口: 由于二级缓存中的对象是以序列化的形式存储的,所有被缓存的对象必须实现 Serializable 接口。

二级缓存的示例
  1. Mapper 映射文件中启用二级缓存

<mapper namespace="com.example.mapper.UserMapper"><cache/><select id="selectUser" parameterType="int" resultType="com.example.User">SELECT * FROM user WHERE id = #{id}</select>
</mapper>

Java 代码示例

java">SqlSession sqlSession1 = sqlSessionFactory.openSession();
User user1 = sqlSession1.selectOne("com.example.mapper.UserMapper.selectUser", 1);
sqlSession1.close(); // 查询结果存入二级缓存SqlSession sqlSession2 = sqlSessionFactory.openSession();
User user2 = sqlSession2.selectOne("com.example.mapper.UserMapper.selectUser", 1);
sqlSession2.close(); // 直接从二级缓存中获取结果,不再查询数据库

3. 一级缓存与二级缓存的区别

4. 二级缓存的实现原理

二级缓存是基于持久化的缓存机制实现的,缓存数据可以存储到磁盘或内存中。MyBatis 通过 Cache 接口提供二级缓存的基本操作,开发者可以自定义缓存实现。常见的实现有:

  • PerpetualCache:MyBatis 默认的缓存实现,使用 HashMap 存储数据。
  • LRU (Least Recently Used):最近最少使用算法。
  • FIFO (First In First Out):先进先出算法。
  • Soft Cache:基于 Java 的软引用,缓存会在内存不足时自动清除。
  • Weak Cache:基于 Java 的弱引用,缓存会在下一次 GC 时自动清除。

5. 总结

  • 一级缓存 是 MyBatis 默认开启的 SqlSession 级别的缓存,在同一个 SqlSession 中重复查询相同数据时,使用缓存。
  • 二级缓存Mapper 级别的缓存,需要手动配置,可以在不同的 SqlSession 中共享查询结果。
  • 二级缓存需要开发者确保数据的一致性,因为二级缓存跨 SqlSession 共享,可能导致旧数据在缓存中被使用。

http://www.ppmy.cn/news/1541671.html

相关文章

十五、【智能体】消息节点:流式与非流式输出的比较分析

想象一个我们使用电脑场景&#xff1a;当我们在copy一个很大的文件&#xff0c;电脑会显示“正在复制”&#xff0c;然后还有一个进度条。 在智能体中&#xff0c;消息节点的作用是告知用户当前任务执行到什么阶段了&#xff0c;起一个提示作用。 在扣子中&#xff0c;消息的输…

CSS学习(Grid布局和flex布局比较)

grid网格布局真香&#xff0c;比flex方便太多了&#xff0c;grid-template-columns用法 文章目录 flex布局的时候网格grid布局的时候可以修改某一列的像素可以修改某一列的宽度占比自适应屏幕分列让第一个元素长宽都占2个 flex布局的时候 最后一行不够4个的时候 最下面一行无法…

图书库存控制:Spring Boot进销存系统的应用

2相关技术 2.1 MYSQL数据库 MySQL是一个真正的多用户、多线程SQL数据库服务器。 是基于SQL的客户/服务器模式的关系数据库管理系统&#xff0c;它的有点有有功能强大、使用简单、管理方便、安全可靠性高、运行速度快、多线程、跨平台性、完全网络化、稳定性等&#xff0c;非常…

android黑屏问题记录

近期出现了一个黑屏问题&#xff1a; 仪表显示&#xff0c;主副屏黑的 &#xff1a;原因背光开启太晚&#xff0c;导致拍照时候是黑的&#xff0c;太晚的原因是绘制进程出现异常导致重启延后了时间&#xff0c;绘制进程crash原因是hwc调用底层库卡住&#xff0c;需更新hwc对应的…

Java处理大数据小技巧:深入探讨与实践

引言 一、选择合适的数据结构 1. 使用高效的集合 2. 并发安全的数据结构 二、内存管理 1. JVM参数调优 2. 避免内存泄漏 三、并行计算与分布式处理 1. 利用Java并发API 2. 分布式框架 四、数据压缩与序列化 1. 数据压缩 2. 高效序列化 五、外部存储与缓存 1. NoS…

基于Java微信小程序的高校教务管理系统的详细设计和实现(源码+lw+部署文档+讲解等)

详细视频演示 请联系我获取更详细的演示视频 项目运行截图 技术框架 后端采用SpringBoot框架 Spring Boot 是一个用于快速开发基于 Spring 框架的应用程序的开源框架。它采用约定大于配置的理念&#xff0c;提供了一套默认的配置&#xff0c;让开发者可以更专注于业务逻辑而不…

JavaScript初级课程 variables

下载node。 1. 申明变量 variables.js let message "Hello!"; message "World"; console.log(message);node variables.js2. 申明不会变的变量 const COLOR_GREEN "green"; console.log(COLOR_GREEN)3. 数据类型 Data Types [number, B…

[MySQL]第一章:环境安装

本专栏内容为&#xff1a;java学习专栏 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;MySql &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 目录 卸载…