MyBatis 完整知识体系
一、核心配置文件
1. application.yml 配置
mybatis:
mapper-locations: classpath:mapper/*.xml
type-aliases-package: com.fitow.system.entity
configuration:
map-underscore-to-camel-case: true
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
lazy-loading-enabled: true
aggressive-lazy-loading: false
2. mybatis-config.xml(传统方式)
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configuration
PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<setting name="mapUnderscoreToCamelCase" value="true"/>
<setting name="logImpl" value="STDOUT_LOGGING"/>
</settings>
<typeAliases>
<package name="com.fitow.system.entity"/>
</typeAliases>
</configuration>
二、Mapper XML 基本结构
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.fitow.system.mapper.SysMenuMapper">
</mapper>
要点:
namespace 必须是对应的 Mapper 接口全路径
- 一个 XML 对应一个 Mapper 接口
三、四种基本操作标签
1. <select> - 查询
<select id="findById" resultType="SysMenu">
SELECT * FROM sys_menu WHERE id = #{id}
</select>
<select id="findAll" resultType="SysMenu">
SELECT * FROM sys_menu
</select>
<select id="search" resultType="SysMenu">
SELECT * FROM sys_menu
WHERE label LIKE CONCAT('%', #{keyword}, '%')
</select>
2. <insert> - 插入
<insert id="insert">
INSERT INTO sys_menu(label, path, menu_type)
VALUES(#{label}, #{path}, #{menuType})
</insert>
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
INSERT INTO sys_menu(label, path, menu_type)
VALUES(#{label}, #{path}, #{menuType})
</insert>
<insert id="batchInsert">
INSERT INTO sys_menu(label, path, menu_type) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.label}, #{item.path}, #{item.menuType})
</foreach>
</insert>
3. <update> - 更新
<update id="updateById">
UPDATE sys_menu
SET label = #{label},
path = #{path},
menu_type = #{menuType}
WHERE id = #{id}
</update>
4. <delete> - 删除
<delete id="deleteById">
DELETE FROM sys_menu WHERE id = #{id}
</delete>
<delete id="deleteBatch">
DELETE FROM sys_menu WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</delete>
四、参数传递
1. #{} - 预编译(推荐,防SQL注入)
<select id="findByName" resultType="SysMenu">
SELECT * FROM sys_menu WHERE label = #{name}
</select>
2. ${} - 字符串拼接(慎用,有SQL注入风险)
<select id="findByColumn" resultType="SysMenu">
SELECT * FROM sys_menu ORDER BY ${column}
</select>
3. 多参数传递
List<SysMenu> findByTypeAndStatus(@Param("type") Integer type,
@Param("status") Integer status);
<select id="findByTypeAndStatus" resultType="SysMenu">
SELECT * FROM sys_menu
WHERE menu_type = #{type} AND noshow = #{status}
</select>
4. Map 传参
List<SysMenu> findByMap(Map<String, Object> params);
<select id="findByMap" resultType="SysMenu">
SELECT * FROM sys_menu
WHERE menu_type = #{type} AND label LIKE CONCAT('%', #{keyword}, '%')
</select>
五、resultType vs resultMap
1. resultType(简单映射)
<select id="findAll" resultType="com.fitow.system.entity.SysMenu">
SELECT * FROM sys_menu
</select>
2. resultMap(复杂映射)
<resultMap id="menuMap" type="SysMenu">
<id column="id" property="id"/>
<result column="label" property="label"/>
<result column="menu_type" property="menuType"/>
<result column="create_time" property="createTime"/>
</resultMap>
<select id="findById" resultMap="menuMap">
SELECT * FROM sys_menu WHERE id = #{id}
</select>
六、动态 SQL(核心技能)
1. <if> - 条件判断
<select id="search" resultType="SysMenu">
SELECT * FROM sys_menu WHERE 1=1
<if test="label != null and label != ''">
AND label LIKE CONCAT('%', #{label}, '%')
</if>
<if test="menuType != null">
AND menu_type = #{menuType}
</if>
</select>
2. <where> - 动态 WHERE(自动处理 AND/OR)
<select id="search" resultType="SysMenu">
SELECT * FROM sys_menu
<where>
<if test="label != null">
AND label LIKE CONCAT('%', #{label}, '%')
</if>
<if test="menuType != null">
AND menu_type = #{menuType}
</if>
</where>
</select>
3. <set> - 动态更新(自动去逗号)
<update id="updateSelective">
UPDATE sys_menu
<set>
<if test="label != null">label = #{label},</if>
<if test="path != null">path = #{path},</if>
<if test="menuType != null">menu_type = #{menuType},</if>
</set>
WHERE id = #{id}
</update>
4. <foreach> - 循环遍历
<select id="findByIds" resultType="SysMenu">
SELECT * FROM sys_menu WHERE id IN
<foreach collection="ids" item="id" open="(" separator="," close=")">
#{id}
</foreach>
</select>
<insert id="batchInsert">
INSERT INTO sys_menu(label, path) VALUES
<foreach collection="list" item="item" separator=",">
(#{item.label}, #{item.path})
</foreach>
</insert>
5. <choose>/<when>/<otherwise> - 条件分支
<select id="findAll" resultType="SysMenu">
SELECT * FROM sys_menu
ORDER BY
<choose>
<when test="sortField == 'createTime'">
create_time DESC
</when>
<when test="sortField == 'sort'">
sort ASC
</when>
<otherwise>
id ASC
</otherwise>
</choose>
</select>
6. <sql>/<include> - SQL 片段复用
<sql id="baseColumns">
id, label, path, menu_type, create_time
</sql>
<sql id="whereClause">
<where>
<if test="label != null">
AND label LIKE CONCAT('%', #{label}, '%')
</if>
</where>
</sql>
<select id="findAll" resultType="SysMenu">
SELECT <include refid="baseColumns"/>
FROM sys_menu
<include refid="whereClause"/>
</select>
七、关联查询
1. 一对一(<association>)
public class Order {
private Long id;
private User user;
}
<resultMap id="orderMap" type="Order">
<id column="id" property="id"/>
<association property="user" javaType="User">
<id column="user_id" property="id"/>
<result column="user_name" property="name"/>
</association>
</resultMap>
<select id="findOrderWithUser" resultMap="orderMap">
SELECT o.*, u.id AS user_id, u.name AS user_name
FROM orders o
LEFT JOIN user u ON o.user_id = u.id
</select>
2. 一对多(<collection>)- 嵌套查询
<resultMap id="menuTreeMap" type="SysMenu">
<id column="id" property="id"/>
<collection property="children"
ofType="SysMenu"
column="id"
select="selectChildrenByParentId"/>
</resultMap>
<select id="selectChildrenByParentId" resultType="SysMenu">
SELECT * FROM sys_menu WHERE parent_id = #{parentId}
</select>
<select id="selectMenuTree" resultMap="menuTreeMap">
SELECT * FROM sys_menu WHERE parent_id IS NULL
</select>
3. 一对多(<collection>)- 联合查询
<resultMap id="menuWithButtonsMap" type="MenuWithButtonsDTO">
<id column="id" property="id"/>
<result column="label" property="label"/>
<collection property="buttons" ofType="ButtonDTO">
<id column="button_id" property="id"/>
<result column="button_name" property="name"/>
</collection>
</resultMap>
<select id="selectMenuWithButtons" resultMap="menuWithButtonsMap">
SELECT m.*, b.id AS button_id, b.name AS button_name
FROM sys_menu m
LEFT JOIN sys_button b ON m.id = b.menu_id
</select>
八、分页查询
1. 手动分页(MySQL)
<select id="pageList" resultType="SysMenu">
SELECT * FROM sys_menu
<where>
<if test="label != null">
AND label LIKE CONCAT('%', #{label}, '%')
</if>
</where>
ORDER BY sort ASC
LIMIT #{offset}, #{pageSize}
</select>
2. PageHelper 分页(推荐)
<dependency>
<groupId>com.github.pagehelper</groupId>
<artifactId>pagehelper-spring-boot-starter</artifactId>
<version>1.4.6</version>
</dependency>
PageHelper.startPage(pageNum, pageSize);
List<SysMenu> list = sysMenuMapper.findAll();
PageInfo<SysMenu> pageInfo = new PageInfo<>(list);
pageInfo.getTotal();
pageInfo.getPages();
pageInfo.getList();
九、缓存
1. 一级缓存(默认开启,SqlSession 级别)
2. 二级缓存(Mapper 级别)
<mapper namespace="com.fitow.system.mapper.SysMenuMapper">
<cache eviction="LRU" flushInterval="60000" size="512" readOnly="true"/>
</mapper>
十、MyBatis vs MyBatis-Plus 对比
| 对比项 |
MyBatis |
MyBatis-Plus |
| 基础CRUD |
手写 SQL |
自动生成 |
| 动态SQL |
手写 <if>、<where> |
LambdaQueryWrapper |
| 分页 |
手写 LIMIT 或 PageHelper |
this.page() |
| 逻辑删除 |
手写条件 |
@TableLogic 自动处理 |
| 乐观锁 |
手写 version 判断 |
@Version 自动处理 |
| 自动填充 |
手写 |
MetaObjectHandler |
| 代码量 |
多 |
少(减少约70%) |
| 灵活性 |
高(完全控制SQL) |
中(复杂SQL仍需手写) |
十一、使用优先级
第1优先:MyBatis-Plus Service 方法
this.save()、this.list()、this.page()
第2优先:MyBatis-Plus LambdaQueryWrapper
wrapper.eq().like().list()
第3优先:MyBatis XML 基本操作
<select>、<insert>、<update>、<delete>
第4优先:MyBatis XML 动态SQL
<if>、<where>、<foreach>、<set>
第5优先:MyBatis XML 关联查询
<association>、<collection>
十二、快速记忆口诀
四个标签要记牢:select insert update delete
参数传递用井号:#{} 安全又可靠
动态SQL三件套:if where foreach
结果映射两兄弟:resultType 简单,resultMap 复杂
关联查询两招:association 一对一,collection 一对多
代码复用靠 sql + include
条件分支 choose when otherwise
这份 MyBatis 笔记和 MP 那套结构一样,覆盖了 MyBatis 全部核心知识点,日常开发够用了。
一、MyBatis XML 常用标签(最重要)
| 标签 |
作用 |
<select> |
查询 SQL |
<insert> |
插入 SQL |
<update> |
更新 SQL |
<delete> |
删除 SQL |
<resultMap> |
结果集映射 |
<parameterMap> |
参数映射(已不推荐) |
<sql> |
定义可复用 SQL 片段 |
<include> |
引入 SQL 片段 |
<cache> |
二级缓存配置 |
<cache-ref> |
引用其他 namespace 的缓存 |
二、动态 SQL 关键字(高频考点)
| 标签 |
说明 |
<if> |
条件判断 |
<choose> / <when> / <otherwise> |
类似 switch-case |
<trim> |
去多余逗号/AND/OR |
<where> |
自动处理 WHERE |
<set> |
自动处理 SET |
<foreach> |
遍历集合(IN、批量) |
<bind> |
绑定变量(常用于模糊查询) |
✅ 示例(<where> + <if>):
<select id="selectUser">
SELECT * FROM user
<where>
<if test="name != null">
AND name = #{name}
</if>
</where>
</select>
三、SQL 中 MyBatis 常用关键字(结合 JDBC)
| 关键字 |
说明 |
#{} |
预编译参数(防 SQL 注入 ✅) |
${} |
字符串拼接(有注入风险 ⚠️) |
resultType |
返回类型 |
resultMap |
自定义结果映射 |
parameterType |
参数类型 |
useGeneratedKeys |
获取自增主键 |
keyProperty |
主键字段 |
keyColumn |
数据库主键列 |
flushCache |
是否刷新缓存 |
useCache |
是否使用二级缓存 |
timeout |
SQL 超时时间 |
fetchSize |
JDBC fetchSize |
四、Mapper 接口相关关键字(注解)
| 注解 |
说明 |
@Select |
查询 |
@Insert |
插入 |
@Update |
更新 |
@Delete |
删除 |
@Param |
给参数命名 |
@Result |
字段映射 |
@Results |
多个 Result |
@One |
一对一 |
@Many |
一对多 |
五、关联映射关键字(ResultMap)
| 标签 |
说明 |
<id> |
主键 |
<result> |
普通字段 |
<association> |
一对一 |
<collection> |
一对多 |
columnPrefix |
列前缀 |
lazyLoadingEnabled |
延迟加载 |
aggressiveLazyLoading |
侵入式懒加载 |
六、MyBatis 核心配置(mybatis-config.xml)
| 配置项 |
说明 |
<configuration> |
根标签 |
<environments> |
环境配置 |
<environment> |
单个环境 |
<transactionManager> |
事务管理器 |
<dataSource> |
数据源 |
<mappers> |
Mapper 扫描 |
<typeAliases> |
别名 |
<plugins> |
插件(分页、拦截器) |
七、常见面试一句话总结 ✅
MyBatis 常用关键字 = SQL 关键字 + 动态 SQL 标签 + #{} / ${} + resultMap + 缓存配置
所有评论(0)