Mybatis基础
一、MyBatis 核心基础 🔴
1、MyBatis 是什么
MyBatis 是一款轻量级、半自动ORM持久层框架。自定义SQL、灵活度高、性能优秀,支持高级映射、延迟加载、缓存、插件扩展,是互联网行业主流持久层框架。
半自动ORM:手写SQL(灵活)+ 自动封装结果集(简化代码)。
2、核心九大组件 🔴
-
Configuration:全局配置类,加载所有xml、注解、环境配置。
-
SqlSessionFactory:会话工厂,生产SqlSession,全局单例。
-
SqlSession:数据库会话,负责CRUD,非线程安全,用完关闭。
-
Executor:执行器,SQL调度核心,处理缓存、事务。
-
MappedStatement:封装一条SQL语句、ID、参数、返回值。
-
ParameterHandler:参数预处理、赋值、防止注入。
-
StatementHandler:封装JDBC Statement,执行SQL。
-
ResultSetHandler:结果集封装,映射为Java对象。
-
TypeHandler:类型转换器,Java类型 <=> 数据库类型。
3、完整执行流程 🔴
-
加载核心配置文件,初始化Configuration全局配置;
-
构建SqlSessionFactory工厂对象;
-
获取SqlSession会话,默认开启事务、不自动提交;
-
通过动态代理生成Mapper接口代理对象;
-
Executor执行器获取MappedStatement,封装SQL;
-
ParameterHandler完成参数预编译赋值;
-
StatementHandler执行JDBC SQL;
-
ResultSetHandler反射封装结果集;
-
关闭会话、释放资源,事务手动提交。
二、语法核心考点 🔴
1、#{} 和 ${} 硬核区别 🔴
| 对比项 | #{} 预编译占位符 | ${} 字符串直接拼接 |
|---|---|---|
| 编译方式 | 预编译、生成?占位符 | 直接字符串拼接SQL |
| 安全性能 | 防SQL注入(底层PreparedStatement) | 存在严重注入风险 |
| 数据类型 | 自动加单引号 | 原样拼接,不加引号 |
| 使用场景 | 普通条件查询(99%场景) | 动态表名、排序字段 |
生产强制规范:优先使用#{},禁止随意使用${}。
2、动态SQL标签(生产常用)
-
if:非空判断,动态拼接条件。
-
where:自动去除多余and/or,避免语法报错。
-
set:更新语句,自动去除尾部逗号。
-
foreach:批量遍历,in查询、批量插入。
-
trim:自定义截取前后多余字符,万能标签。
-
bind:绑定变量,拼接模糊查询,防止数据库兼容问题。
3、resultType 和 ResultMap 区别
-
resultType:简单类型、实体类,自动映射,要求字段名和属性名一致。
-
resultMap:自定义映射,解决字段不一致、复杂关联、嵌套查询、类型转换。
三、关联查询 & 懒加载 🔴
1、三种关联关系
-
一对一:用户-用户详情,association标签。
-
一对多:订单-订单项,collection标签。
-
多对多:用户-角色,中间表拆分,转化为一对多。
2、两种查询方式
(1)嵌套结果查询(联表查询)
一条SQL联表查询,一次性查出所有数据,性能高,适合数据量小场景。
(2)嵌套查询(分步查询)
先查主表,再查关联表,SQL多条,配合懒加载优化性能。
3、N+1 查询问题 🟠
3.1 现象
查询10条用户,额外执行10条SQL查询关联订单,一共11次SQL查询。
3.2 解决方案
-
使用联表嵌套结果,一条SQL搞定;
-
开启懒加载,按需加载关联数据;
-
禁止循环中单独查询数据库。
4、懒加载机制
-
核心配置:lazyLoadingEnabled=true,默认关闭。
-
原理:分步查询时,默认不加载关联数据,使用属性时才触发查询。
-
优点:减少无效SQL,提升查询性能。
四、缓存机制 🔴
1、一级缓存(本地缓存)
1.1 特性
-
默认开启,无需手动配置。
-
作用域:同一个SqlSession。
-
缓存位置:内存,底层HashMap。
1.2 失效场景 🔴
-
SqlSession手动关闭、清空;
-
执行增删改操作(自动清空缓存);
-
手动调用clearCache()。
2、二级缓存(全局缓存)
2.1 特性
-
默认关闭,需要手动开启。
-
作用域:同一个Mapper映射文件,跨SqlSession共享。
-
底层:默认PerpetualCache,内存存储。
2.2 开启条件(全部满足)
-
全局配置开启:cacheEnabled=true;
-
Mapper文件添加 <cache/> 标签;
-
实体类实现序列化接口Serializable;
-
SqlSession正常关闭,缓存才写入二级缓存。
2.3 执行顺序
二级缓存 → 一级缓存 → 数据库
3、缓存穿透、击穿、雪崩(Mybatis层面)
-
穿透:查询不存在数据,缓存不存储,直连数据库 → 空值缓存。
-
击穿:热点数据缓存失效,大量请求打库 → 延长缓存时间。
-
雪崩:大量缓存同时失效 → 过期时间随机偏移。
五、插件机制(高级工程师必懂)
1、四大拦截对象(拦截顺序)
Mybatis仅允许拦截四大核心对象,无法拦截其他组件:
-
Executor:执行器,拦截增删改查、事务(最先拦截)。
-
ParameterHandler:参数赋值拦截。
-
StatementHandler:SQL语句修改、分页改写(PageHelper原理)。
-
ResultSetHandler:结果集封装、后置处理。
2、插件开发原理
-
实现Interceptor拦截器接口;
-
注解指定拦截签名、拦截方法;
-
生成JDK动态代理,对目标对象增强;
-
插件链逐层执行,责任链模式。
3、生产常用插件
-
PageHelper:分页插件,改写SQL拼接limit;
-
通用Mapper:简化CRUD;
-
自定义数据脱敏、字段加密插件。
六、事务 & 批量操作(生产重点)
1、事务管理
-
Mybatis默认开启手动事务,不自动提交;
-
整合Spring后,交由Spring事务管理器控制;
-
传播行为、隔离级别完全依赖Spring。
2、批量操作优化
2.1 普通foreach批量(不推荐)
拼接多条insert语句,SQL过长、数据库解析压力大。
2.2 SqlSession批量模式(生产推荐)
开启批量Executor,底层攒SQL,一次性提交数据库,减少IO次数。
|
|
七、生产高频坑点 🔴
-
驼峰命名失效:未开启mapUnderscoreToCamelCase,数据库下划线无法映射Java驼峰属性。
-
一级缓存脏数据:同会话查询、中间无修改,读取缓存旧数据,分布式环境建议关闭一级缓存。
-
二级缓存脏数据:多Mapper修改同一张表,缓存不互通,出现脏数据。
-
foreach批量过多:in查询参数过长,超出数据库max_allowed_packet限制。
-
时间类型异常:未配置时区、类型处理器,日期时差8小时。
-
空字符串判断:if标签判断''空字符串,引发查询逻辑异常。
八、高级优化方案 🔴
-
禁止select *:明确查询字段,减少IO、减少内存占用。
-
合理使用分页:禁止一次性查询全表大数据。
-
关闭不必要缓存:分布式环境关闭一级、二级缓存,避免脏数据,改用Redis缓存。
-
批量操作使用Batch模式:减少数据库连接次数。
-
开启预编译:防止SQL注入,复用执行计划。
-
避免大事务:拆分长事务,减少数据库锁等待。
-
SQL优化:联表代替子查询,避免嵌套循环查询。
九、总结
MyBatis是半自动ORM持久层框架,核心包含九大组件,执行流程分为配置加载、会话创建、SQL解析、参数处理、执行封装;
#{}预编译防注入,${}仅用于动态表名;拥有一级、二级两级缓存,分布式环境建议关闭原生缓存改用Redis;
支持动态SQL、关联查询与懒加载,需规避N+1查询问题;
基于四大拦截对象实现插件扩展,生产常用批量执行器优化批量插入,同时规避缓存脏数据、SQL过长、映射异常等坑点,配合Spring事务完成数据库持久化操作。