MyBatis
约 1442 字大约 5 分钟
2026-04-04
[TOC]
Mybatis的缓存机制
说说 MyBatis 的缓存机制? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
一级缓存
仅在同一个SqlSession中生效。基于namespace、sql、参数作为唯一标识
默认开启,生命周期与SqlSession一致
执行commit、rollback或手动清理缓存时会清空
二级缓存
跨SqlSession共享缓存,基于Mapper的缓存
需要手动开启
<mapper namespace="com.example.mapper.UserMapper">
<!-- 开启二级缓存 -->
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
</mapper>
<!-- eviction:缓存清理策略
flushInterval:刷新间隔
size:缓存的最大对象个数
readOnly:只读,设置为true时提高性能,但不能修改返回对象-->生命周期与SqlSessionFactory一致
数据的增,删,改会清空缓存
一级、二级缓存都会导致脏数据
由于SqlSession会有脏数据的情况,所以我们可以设置SqlSession数据缓存的级别。一共有两种级别分别是SESSION和STATEMENT。SESSION:这是默认设置,意味着在一个SqlSession生命周期内,对查询结果进行缓存。
STATEMENT:意味着每次执行完SQL后都会清除缓存,即每个语句执行后都不会保留缓存。一般建议设置为STATEMENT
MyBatis的执行流程
能详细说说 MyBatis 的执行流程吗? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
- 创建SqlSessionFactory:读取MyBatis的mybatis-configxml初始化,通过SqlSessionFactoryBuilder构建
- 获取SqlSession:SqlSessionFactory通过openSession()获取SqlSession对象(执行sql、提交事务)
- 命名空间和映射语句的查找:通过namespace和id定位,将映射文件解析为一个MappedStatement对象(保存sql、参数类型、返回类型)
- 参数封装、sql语句执行、返回结果映射:sql执行前,根据映射文件配置的parameterType类型,将传入的参数封装为对象。根据不同的执行环境将sql语句执行到数据库中,并将查询结果根据resultType/resultMap进行转换,将查询结果转换为Java对象
- 事务管理:通过SqlSession处理,commit()和rollback()
- 关闭SqlSession:通过close()关闭
MyBatis写个XML映射文件,再写个Dao接口就能执行,原理是什么
MyBatis 写个 Xml 映射文件,再写个 DAO 接口就能执行,这个原理是什么? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
通过动态代理,解析xml映射文件和动态生成dao接口实现类来执行sql
- 加载配置和mapper映射文件:MappedStatement对象
- 动态代理实现dao接口:为每一个dao接口生成代理类MapperProxy,拦截接口方法调用,根据方法名和参数匹配到对应的MappedStatement,调用jdbc执行
- 通过jdbc执行sql:执行sql获取resultset
- 结果映射:resultmap或resulttype映射为dao接口方法的返回值类型
MyBatis支持延迟加载
MyBatis 是否支持延迟加载?如果支持,它的实现原理是什么? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
通过MyBatis提供的代理对象,当访问具体关联的属性时,才真正触发数据库的查询
<settings>
<!-- 启用懒加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 当访问任何属性时,都会加载所有懒加载属性 -->
<setting name="aggressiveLazyLoading" value="false"/>
<!-- 使用实际的参数而不是当前对象的哈希码来触发加载 -->
<setting name="useActualParamName" value="true"/>
</settings>使用CGLIB或Javassist创建代理对象
代理对象内部维护一个延迟加载器ResultLoaderMap记录哪些属性需要延迟加载
进入代理对象的invoke,检查被调用方法是否是延迟加载属性的getter方法,如果是,并且该属性的值为null,执行sql查询,再setter设置到目标对象的属性中
mybatis插件的运行原理
简述 MyBatis 的插件运行原理,以及如何编写一个插件? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
通过动态代理实现,在sql执行的关键点拦截生成代理对象。先调用插件的intercept
ExecutorL:执行sql CRUD操作
ParameterHandler:处理sql语句中的参数
StatementHandler:处理sql语句
ResultSetHandler:处理结果集
实现
实现Intercept接口
- intercept:拦截逻辑
- plugin:创建当前拦截器的代理对象
- setProperties:设置插件属性
定义拦截逻辑
在intercept实现增强逻辑。使用Invocation对象调用目标方法
配置插件
在mybatis-config.xml配置插件类和参数
@Intercepts({
@Signature(
type= StatementHandler.class,
method = "prepare",
args = {Connection.class, Integer.class}
)
})
public class ExamplePlugin implements Interceptor {
@Override
public Object intercept(Invocation invocation) throws Throwable {
// 获取被代理对象
StatementHandler statementHandler = (StatementHandler) invocation.getTarget();
// 获取 SQL 语句
String sql = statementHandler.getBoundSql().getSql();
System.out.println("SQL: " + sql);
// 继续执行其他插件链和目标方法
return invocation.proceed();
}
@Override
public Object plugin(Object target) {
// 创建代理对象
return Plugin.wrap(target, this);
}
@Override
public void setProperties(Properties properties) {
// 从配置中获取属性,例如:
String someProperty = properties.getProperty("someProperty");
System.out.println("Some Property: " + someProperty);
}
}<plugins>
<plugin interceptor="com.example.ExamplePlugin">
<property name="someProperty" value="value"/>
</plugin>
</plugins>用途
性能分析、动态参数注入、数据脱敏、自动分页
mybatis实现数据库类型和java类型转换
MyBatis 如何实现数据库类型和 Java 类型的转换的? - MyBatis 面试题 - 面试鸭 - 程序员求职面试刷题神器
依赖类型处理器TypeHandler
加载映射文件时,根据jdbc类型和java类型确定使用的TypeHandler
执行sql时,ParameterHandler使用TypeHandler将java参数转换为jdbc类型
解析结果集时,ResultSetHandler使用TypeHandler将jdbc类型转换为java对象
贡献者
更新日志
fb8bc-更新为vuepress于