大家好我是小明,今天学习mybatis
文章目录
- [1. MyBatis执行流程](#1. MyBatis执行流程)
- [2. MyBatis是否支持延迟加载](#2. MyBatis是否支持延迟加载)
- [3. MyBtis的一级缓存,二级缓存](#3. MyBtis的一级缓存,二级缓存)
- [🎯4. MyBatis 中 #{} 和 {} 的核心区别](#{} 和 {} 的核心区别)
1. MyBatis执行流程
大体流程

这个更详细:

讲解一下这个流程:
初始化阶段:服务器启动时会加载mybatis-config.xml文件(现在boot项目也可以使用applicationyml文件来配置数据信息),然后构建会话工厂sqlSessionFactroy
运行时阶段:会话工厂sqlSessionFactroy会创建一个SqlSession对象(相当于「数据库会话」,非线程安全,每次请求 / 方法调用都要新建),SqlSession 封装了数据库连接和执行 SQL 的方法,把对象交给Executor执行器来操作数据库,Executor接口的执行方法中有一个MappedStatement参数类型对象记录映射信息(resultType,还有一些入参数).
MyBatis执行流程
- 读取 MyBatis 配置文件:mybatis-config.xml 加载运行环境和映射文件
- 构造会话工厂 SqlSessionFactory
- 会话工厂创建 SqlSession 对象(包含了执行 SQL 语句的所有方法)
- 操作数据库的接口,Executor 执行器,同时负责查询缓存的维护
- Executor 接口的执行方法中有一个 MappedStatement 类型的参数,封装了映射信息
- 输入参数映射
- 输出结果映射
2. MyBatis是否支持延迟加载
答:支持但是默认是没有开启
什么叫延迟加载??
举一个例子:

即:按需加载
来看一个代码

这个代码是执行selectById方法之后会立马执行,图片红色方框中的findByUid方法将该用户的订单全部查询出来。
可以修改一个属性fetchType=lazy开启延迟加载。

我们来看一个案例

我们注释掉一段代码看看
看这里就是不查询第二条sql只查询第一条,只有我们需要的时候在查询。
这个fatchtype属性也可以修改成全局的。
延迟加载的底层原理

3. MyBtis的一级缓存,二级缓存
- 一级缓存(本地缓存)
默认是开启的
作用范围: SqlSession 级别,即同一个数据库会话内有效。
生命周期: 和 SqlSession 绑定,SqlSession 关闭或提交 / 回滚事务时,一级缓存就会被清空。
核心原理:
- 第一次执行 userMapper.selectById(1) 时,MyBatis 会去数据库查询,同时把结果存入当前 SqlSession 的一级缓存中。
- 同一个 SqlSession 内再次执行相同的查询,会直接从缓存中取结果,不再访问数据库。
触发清空缓存的场景:
- 执行 update/delete/insert 等写操作时,MyBatis 会自动清空当前 SqlSession 的一级缓存,避免脏数据。
- 调用 sqlSession.clearCache() 手动清空。
- SqlSession 关闭或事务提交 / 回滚。
例子:

2. 二级缓存
默认是关闭的
在配置文件中添加配置cacheEnabled=true开启
作用范围: Mapper 级别(namespace 级别),同一个 namespace(是存储SqlSession 的hashMap) 下的所有 SqlSession 共享缓存。
生命周期: 和 SqlSessionFactory 绑定,只要工厂不关闭,缓存就会一直存在(可配置过期时间)
核心原理:
- 第一次查询后,结果会先存入一级缓存;当 SqlSession 关闭时,一级缓存的内容会被同步到二级缓存。
- 其他 SqlSession 执行相同 namespace 下的相同查询时,会直接从二级缓存中取结果。
注意事项:
- 只有 SqlSession 关闭或提交后,一级缓存的数据才会进入二级缓存。
- 执行写操作(update/delete/insert)时,会清空当前 namespace 下的二级缓存。
- 缓存的对象需要实现 Serializable 接口,因为二级缓存可能会被序列化到磁盘或跨进程共享。
例子

正常来说,会执行两次sql,开启二级缓存后sql会执行一次会话关闭后,数据从一级缓存到二级缓存,第二次会从二级缓存里面拿数据。
🎯4. MyBatis 中 #{} 和 ${} 的核心区别
#{name}(预编译占位符)
原理: MyBatis 会把 #{name} 解析成 JDBC 的 ? 占位符,在执行 SQL 前通过 PreparedStatement 预编译,再把参数值安全地设置到占位符中。
安全性: 可以有效防止 SQL 注入,因为参数值是通过 setXxx() 方法设置的。
${name}(字符串直接替换)
原理: MyBatis 会直接把 ${name} 替换成参数的原始字符串,相当于字符串拼接,不会经过预编译处理。
安全性: 存在 SQL 注入风险,因为参数会直接嵌入 SQL 语句中。
好了今天就到这里