MyBatis 超详细入门实战教程(零基础吃透增删改查)
哈喽!本文将从零带大家吃透 MyBatis 核心知识点,从底层优势、快速入门、Mapper 代理开发,到配置文件实现全套增删改查、参数封装原理、注解开发,全程搭配实战代码示例,重点难点逐一拆解,适合零基础入门、面试复盘、项目实操。
一、MyBatis 核心概述
1.1 什么是 MyBatis?
MyBatis 是一款优秀的开源持久层框架,专门用于简化 Java JDBC 数据库开发,解决原生 JDBC 开发的各类痛点,是 JavaEE 开发中持久层的主流框架。
1.2 JavaEE 三层架构
JavaEE 标准项目分层,各司其职,MyBatis 专注于持久层开发:
- 表现层(Web层):接收前端请求、响应数据(Controller)
- 业务层(Service层):处理业务逻辑、事务控制(Service)
- 持久层(Dao层):负责和数据库交互,完成数据存取(Dao/Mapper),MyBatis 框架作用于此层
1.3 原生 JDBC 开发痛点(MyBatis 解决的核心问题)
原生 JDBC 开发繁琐、冗余代码多、维护性差,核心缺点如下:
- 硬编码问题:数据库驱动、连接地址、账号密码、SQL 语句全部写死在代码中,修改需要改源码、重启项目
- 操作繁琐:需要手动加载驱动、创建连接、关闭资源、手动设置 SQL 参数、手动封装查询结果集,重复代码极多
而 MyBatis 通过配置文件解耦硬编码、自动完成参数注入和结果封装,彻底简化 JDBC 操作。
二、MyBatis 快速入门
2.1 入门整体步骤
- 创建数据库表(示例 user 表/brand 表),初始化测试数据
- 创建 Maven 项目,导入 MyBatis、数据库驱动等核心坐标
- 编写 MyBatis 核心配置文件:配置数据库连接信息,解决连接参数硬编码问题
- 编写 SQL 映射文件(Mapper 文件):统一管理所有 SQL 语句,解决 SQL 硬编码问题
- 编写业务代码,完成数据库操作
2.2 核心编码流程
标准 MyBatis 执行流程,固定 4 步:
- 定义数据库对应 POJO 实体类(属性映射表字段)
- 加载 MyBatis 核心配置文件,获取
SqlSessionFactory工厂对象 - 通过工厂获取
SqlSession会话对象,执行 SQL 操作 - 关闭 SqlSession,释放资源
三、Mapper 代理开发(主流开发方式)
原始 MyBatis 需要通过字符串 ID 执行 SQL,存在字符串硬编码、无代码提示、易出错的问题,而 Mapper 代理开发是企业主流用法,通过接口代理自动匹配 SQL,简洁高效、可维护性强。
3.1 原始写法(缺点明显)
// 通过映射文件的 statementId 执行 SQL,字符串硬编码,极易出错
List<User> users = sqlSession.selectList("test.selectAll");
System.out.println(users);
3.2 Mapper 代理写法(推荐)
// 1. 获取 Mapper 接口的代理对象
UserMapper userMapper = sqlSession.getMapper(UserMapper.class);
// 2. 调用接口方法,自动执行对应 SQL,无硬编码、有代码提示
List<User> userList = userMapper.selectAll();
3.3 Mapper 代理核心规则
- Mapper 接口的全限定类名必须和 Mapper 映射文件的
namespace一致 - 接口中的方法名必须和映射文件中 SQL 标签的
id一致 - 方法返回值、参数类型必须和 SQL 配置的返回值、参数类型匹配
四、MyBatis 核心配置文件 & 映射文件详解
4.1 核心配置文件
核心配置文件用于全局配置 MyBatis 环境,包含数据库连接、环境配置、映射文件引入等,彻底解耦数据库硬编码。核心配置项:环境配置、事务管理、连接池、映射文件注册。
4.2 映射文件核心作用
专门用来存放 SQL 语句,统一管理数据层操作,支持动态 SQL、结果映射、参数绑定,是 MyBatis 操作数据库的核心文件。
五、配置文件实现全套增删改查(重点)
5.1 查询操作
5.1.1 基础查询:解决实体类与数据库字段名不一致问题
数据库字段通常下划线命名(brand_name),Java 实体类属性驼峰命名(brandName),默认无法自动封装数据,提供两种解决方案:
方案1:SQL 片段别名(复用性一般)
通过 <sql> 定义通用字段片段,统一起别名,适合简单场景
<!-- 名称空间:绑定对应 Mapper 接口 -->
<mapper namespace="com.hebu.mapper.BrandMapper">
<!-- 定义通用字段片段,统一别名 -->
<sql id="brand_column">
id,brand_name brandName,company_name companyName,ordered,description
</sql>
<!-- 查询所有数据 -->
<select id="selectAll" resultType="brand">
select <include refid="brand_column"/> from tb_brand
</select>
</mapper>
方案2:ResultMap 结果映射(推荐、灵活)
通过 <resultMap> 手动绑定数据库字段与实体类属性,适配所有复杂场景,企业首选
<mapper namespace="com.hebu.mapper.BrandMapper">
<!-- 结果映射:解决字段与属性名不一致 -->
<resultMap id="brandResultMap" type="brand">
<!-- column:数据库字段名,property:实体类属性名 -->
<result column="brand_name" property="brandName"/>
<result column="company_name" property="companyName"/>
</resultMap>
<!-- 查询所有,引用自定义 ResultMap -->
<select id="selectAll" resultMap="brandResultMap">
select * from tb_brand
</select>
</mapper>
5.1.2 单条详情查询 & 参数占位符
参数占位符核心区别(高频面试点)
- #{}:预编译占位符,替换为
?,防止 SQL 注入,日常参数传递首选 - ${}:字符串拼接 SQL,存在 SQL 注入风险,仅用于动态表名、动态列名场景
补充:parameterType 参数类型可省略,MyBatis 可自动推断
详情查询示例
<select id="selectById" resultMap="brandResultMap">
select * from tb_brand where id=#{id}
</select>
特殊字符处理
XML 中 <、> 等特殊字符无法直接使用,两种解决方案:
- 转义字符:< 替代 <,> 替代 >
- CDATA 区:
<![CDATA[ 内容 ]]>包裹特殊语法
5.1.3 多条件动态查询
通过 <if> 标签判断参数是否为空,实现动态拼接 SQL,搭配 <where> 标签自动处理多余 and/or,规避语法错误
参数接收三种方式
- 散装参数:多参数需加
@Param("参数名")绑定占位符 - 对象参数:占位符名称与实体类属性名一致
- Map 参数:占位符名称与 Map 的 key 一致
多条件查询完整示例
<select id="selectByCondition" resultMap="brandResultMap">
select * from tb_brand
<where>
<!-- 非空判断,动态拼接条件 -->
<if test="status!=null">
and status=#{status}
</if>
<if test="brandName!=null and brandName!=''>
and brand_name like #{brandName}
</if>
<if test="companyName!=null and companyName!=''>
and company_name like #{companyName}
</if>
</where>
</select>
5.1.4 单条件单选查询
通过 <choose><when><otherwise> 实现类似 switch-case 效果,只匹配一个条件,优先级从上到下
<select id="selectByConditionSingle" resultMap="brandResultMap">
select * from tb_brand
<where>
<choose>
<when test="status!=null">and status=#{status}</when>
<when test="brandName!=null and brandName!=''>and brand_name like #{brandName}</when>
<when test="companyName!=null and companyName!=''>and company_name like #{companyName}</when>
<!-- 所有条件不匹配时的默认值 -->
<otherwise>1=1</otherwise>
</choose>
</where>
</select>
5.2 新增操作
5.2.1 基础新增
MyBatis 默认需要手动提交事务,调用 sqlSession.commit();可通过 openSession(true) 设置自动提交事务
<insert id="insert">
insert into tb_brand(brand_name,company_name,ordered,description,status)
values(#{brandName},#{companyName},#{ordered},#{description},#{status})
</insert>
5.2.2 主键返回(自增主键)
新增数据后,自动获取数据库自增主键 ID,核心属性:useGeneratedKeys="true" 开启主键返回,keyProperty="id" 绑定实体类主键属性
<insert id="insert" useGeneratedKeys="true" keyProperty="id">
insert into tb_brand(brand_name,company_name,ordered,description,status)
values(#{brandName},#{companyName},#{ordered},#{description},#{status})
</insert>
5.3 修改操作
通过 <set> + <if> 实现动态修改,只更新非空字段,自动去除最后多余的逗号,避免 SQL 语法错误
<update id="update">
update tb_brand
<set>
<if test="brandName!=null and brandName!=''>brand_name=#{brandName},</if>
<if test="companyName!=null and companyName!=''>company_name=#{companyName},</if>
<if test="ordered!=null">ordered=#{ordered},</if>
<if test="description!=null and description!=''>description=#{description},</if>
<if test="status!=null">status=#{status}</if>
</set>
where id=#{id}
</update>
5.4 删除操作
5.4.1 批量删除
MyBatis 会将数组参数封装为 Map 集合,默认 key 为 array,可通过 @Param 自定义 key,搭配 <foreach> 遍历数组实现批量删除
方式1:@Param 自定义参数名(推荐,可读性强)
Mapper 接口方法:
void deletes(@Param("ids") Integer[] ids);
Mapper 映射文件:
<delete id="deletes">
delete from tb_brand where id in
<foreach collection="ids" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
方式2:使用默认 array key
Mapper 接口方法:
void deletes(Integer[] ids);
Mapper 映射文件:
<delete id="deletes">
delete from tb_brand where id in
<foreach collection="array" item="id" separator="," open="(" close=")">
#{id}
</foreach>
</delete>
六、MyBatis 参数封装底层原理
MyBatis 通过 ParamNameResolver 类完成参数封装,核心是将所有参数统一封装为 Map 集合,通过 key 匹配 SQL 占位符。
6.1 单个参数封装规则
- POJO 对象:直接封装,占位符名称与对象属性名一致即可
- Map 集合:直接封装,占位符名称与 Map 的 key 一致
- Collection/List:封装为 Map,默认 key:
collection/list/arg0,推荐用@Param自定义 key - Array 数组:封装为 Map,默认 key:
array/arg0 - 基本类型:直接使用,无需额外处理
6.2 多个参数封装规则
多个参数默认封装为 Map 集合,默认 key 为 arg0、arg1、param1、param2,可读性极差,必须使用 @Param 注解自定义参数名。
七、MyBatis 注解开发
MyBatis 支持注解式开发,无需编写 Mapper 映射文件,代码更简洁,适合简单 CRUD 功能;复杂动态 SQL、多表查询仍推荐配置文件开发。
7.1 注解查询示例
// 通过 @Select 注解直接编写 SQL,无需 xml 文件
@Select("select * from tb_brand where id=#{id}")
Brand selectById(Integer id);
7.2 常用注解
@Select:查询语句@Insert:新增语句@Update:修改语句@Delete:删除语句
八、MyBatis 核心知识点对比表(高频考点)
整理 MyBatis 开发中最容易混淆、面试高频的知识点对比,一目了然,快速区分用法差异:
|
对比维度 |
选项一 |
选项二 |
使用场景 & 核心区别 |
|---|---|---|---|
|
参数占位符 |
#{} 预编译占位符 |
${} 字符串拼接 |
#{}:生成 ? 预编译语句,防止 SQL 注入,适配所有普通参数传递(日常首选);${}:直接拼接 SQL 字符串,有注入风险,仅用于动态表名、动态列名排序字段 |
|
字段映射方案 |
SQL 片段别名 |
ResultMap 映射 |
SQL别名:简单快速、代码复用,但灵活性差,适合固定字段查询;ResultMap:配置一次全局复用、支持复杂映射、灵活度高,企业项目首选 |
|
条件动态查询 |
<if> + <where> 多条件 |
<choose> 单条件 |
<if>:多条件可同时生效,适用于组合筛选、多参数模糊查询;<choose>:单选匹配,只执行一个符合条件的分支,适用于优先级筛选 |
|
数据更新方式 |
普通 update 标签 |
<set> + <if> 动态更新 |
普通更新:全字段覆盖更新,容易覆盖空值;动态更新:只更新非空字段,自动去除多余逗号,适配前端局部修改场景 |
|
开发方式 |
XML 配置文件开发 |
注解开发 |
XML:支持复杂动态 SQL、多表关联、SQL 统一管理,适合复杂业务;注解:代码简洁、无需 XML 文件,仅适合简单单表 CRUD |
|
数组批量参数 |
默认 array 集合key |
@Param 自定义key |
默认array:无需注解,写法简单、可读性差;@Param:自定义参数名称,语义清晰、团队协作友好,企业推荐 |
|
事务提交 |
手动 commit() |
openSession(true) 自动提交 |
手动提交:精准控制事务,支持事务回滚,适配复杂业务;自动提交:简单CRUD快速开发,无需手动提交 |
九、总结
- MyBatis 核心价值:解耦硬编码、简化 JDBC 操作、自动封装结果集
- 主流开发方式:Mapper 代理开发,规避字符串硬编码
- 字段属性不一致解决方案:优先 ResultMap 映射
- 参数占位符:#{} 防注入(常规参数),${} 拼接 SQL(动态表名/列名)
- 动态 SQL 核心标签:、、、、
- 开发选型:简单功能用注解,复杂动态 SQL 用XML 配置文件
更多推荐



所有评论(0)