【MyBatis保姆级教程下】万字XML进阶实战:配置指南与深度解析
目录
1.前言
2.正文
2.1XML文件配置
2.1.1标准框架
2.1.2MybatisX插件
2.1.4基础操作
2.1.4.1查
2.1.4.2增
2.1.4.3改
2.1.4.4删
2.1.3常见报错及解决方案
🚨 2.1.3.1配置文件对应问题
🔍 2.1.3.2字段映射问题
⚙️ 2.1.3.3参数绑定问题
📜 2.1.3.4配置文件语法错误
2.1.4在线diff工具
2.2其他查询操作
2.2.1多表查询
2.2.2慢sql问题
3.小结
1.前言
哈喽大家好吖,今天距离上一次更新已经过了一段时间了,博主也终于从前日的忙碌到现在可以继续静下心创作博客。今天来给大家继续分享的是MyBatis,上一篇没看过的记得看一下哦。【MyBatis保姆级教程上】近万字从零开始手把手教你玩转数据库操作!https://blog.csdn.net/2301_81073317/article/details/148234380?spm=1001.2014.3001.5501
上篇中主要采用的是注解的方式实现数据库操作。今天博文主要包括了通过配置XML文件来实现基础数据库操作,常见报错,在线diff工具,以及其他查询操作讲解,话不多说正文开始。
插播一条消息~
发现一个系统化的人工智能学习平台,涵盖从基础理论到工业级项目实战(人脸识别/自动驾驶/GANs等),内容由浅入深结构清晰,特别适合想体系化提升AI开发能力的朋友,忍不住把干货分享给大家👉
人工智能教学网站https://www.captainbed.cn/scy/
2.正文
2.1XML文件配置
测试数据库:
-- 创建表[用户表]
DROP TABLE IF EXISTS user_info;
CREATE TABLE `user_info` (`id` INT ( 11 ) NOT NULL AUTO_INCREMENT,`username` VARCHAR ( 127 ) NOT NULL,`password` VARCHAR ( 127 ) NOT NULL,`age` TINYINT ( 4 ) NOT NULL,`gender` TINYINT ( 4 ) DEFAULT '0' COMMENT '1-男 2-女 0-默认',`phone` VARCHAR ( 15 ) DEFAULT NULL,`delete_flag` TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',`create_time` DATETIME DEFAULT now(),`update_time` DATETIME DEFAULT now() ON UPDATE now(),PRIMARY KEY ( `id` )
) ENGINE = INNODB DEFAULT CHARSET = utf8mb4;
插入数据:
-- 添加用户信息
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'admin', 'admin', 18, 1, '18612340001' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'zhangsan', 'zhangsan', 18, 1, '18612340002' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'lisi', 'lisi', 18, 1, '18612340003' );
INSERT INTO mybatis_test.user_info( username, `password`, age, gender, phone )
VALUES ( 'wangwu', 'wangwu', 18, 1, '18612340004' );
2.1.1标准框架
上篇我们主要使用了注解进行简单映射。当SQL变得复杂(如动态SQL、结果集映射复杂对象)时,XML配置文件才是王道。它提供了更强大的表达能力和更好的可维护性。
在resources资源包下创建文本文件,记得加上后缀.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.example.mybatis.mapper.UserInfoMapperXML"></mapper>
1. XML声明
作用:声明这是一个XML文档
2. 文档类型定义(DTD)
作用:定义XML文档结构规则
关键功能:
提供XML结构验证
支持IDE智能提示和自动补全
确保MyBatis正确解析XML配置
3. Mapper根元素
<mapper>
:MyBatis XML配置的根元素,所有SQL操作都定义在其中
namespace
属性(绝对核心!):
作用:将XML文件与Java Mapper接口绑定
值要求:必须是Mapper接口的全限定名(包名+类名)
示例解析:
com.example.mybatis.mapper.UserInfoMapperXML
表示:
包路径:
com.example.mybatis.mapper
接口名:
UserInfoMapperXML
4. 内容区域
此处是实际定义SQL操作的位置
可包含的子元素:
<select>
:查询操作
<insert>
:插入操作
<update>
:更新操作
<delete>
:删除操作
<resultMap>
:结果集映射配置
<sql>
:可重用的SQL片段
<cache>
:缓存配置内容区域是我们详细讲的数据库操作部分。
2.1.2MybatisX插件
在正式编写代码前,安装对代码编写有用的开发插件:
MyBatisX 是一款由 MyBatis-Plus 团队开发的 IntelliJ IDEA 插件,专为提升 MyBatis 开发效率设计。它通过智能导航、代码生成、动态提示等功能,显著简化了 Mapper 接口与 XML 文件的开发流程。
官方文档:
MyBatisX官方文档https://baomidou.com/guides/mybatis-x/
在idea设置中找到插件选项,搜索MyBatisX下载并应用,记得重启idea。
核心功能亮点:
双向导航与跳转
在 Mapper 接口方法与 XML SQL 定义之间一键跳转,通过小鸟图标(红色头巾标识接口,蓝色头巾标识 XML)实现无缝切换236。
解决开发中频繁切换文件的问题,提升代码定位效率。
图形化代码生成器
连接数据库后,右键表即可生成 Entity、Mapper 接口、XML 文件、Service 层代码48。
支持多表批量生成,并可自定义包路径、注解(如 Lombok、Swagger)、文件位置等38。
模板自定义:修改
domain.ftl
等模板文件,灵活适配项目规范(例如添加 Swagger 注解)48。JPA 风格方法名提示
根据方法名自动生成 SQL 实现。例如:
findByUsername(String name)
→ 生成SELECT * FROM user WHERE username = #{name}
updateStatusById(Long id, Integer status)
→ 生成更新语句28。输入方法名时自动提示字段,避免手写 SQL 错误。
SQL 辅助工具
智能补全:自动提示表名、字段名、SQL 关键字57。
日志转 SQL:复制 MyBatis 日志中的参数占位符(如
?
),自动转换为完整可执行的 SQL 语句1。XML 校验:实时检查 SQL 语法与映射配置的正确性5。
2.1.4基础操作
查询操作详解,剩下的操作思路大致相同。
2.1.4.1查
Mapper层:
@Mapper
public interface UserInfoMapperXML {List<UserInfo> selectAll();List<UserInfo> selectAll2();
}
model层:
@Data
public class UserInfo {private Integer id;private String username;private String password;private Integer age;private Integer gender;private String phone;private Integer deleteFlag;private Date createTime;private Date updateTime;
}
层和层之间的关系:
在 MyBatis 中主要有三种解决方案解决查询操作。下面通过具体示例详细讲解每种查询实现方式:
1. SQL 别名映射(Alias Mapping)
核心思想:在 SQL 查询语句中直接使用
AS
关键字为字段起别名,使其与 Java 属性名匹配<select id="selectAll" resultType="com.example.mybatis.model.UserInfo">SELECT id, username, `password`, age, gender, phone,delete_flag AS deleteFlag, <!-- 数据库字段 → Java属性 -->create_time AS createTime, <!-- 下划线转驼峰 -->update_time AS updateTime <!-- 字段别名匹配属性名 -->FROM user_info </select>
实现原理:
MyBatis 会将查询结果的列名直接对应到返回类型的属性名
使用
AS
将数据库的蛇形命名(delete_flag
)转换为 Java 的驼峰命名(deleteFlag
)优点:
简单直观,适合简单查询
零配置,无需额外声明
缺点:
SQL 语句冗长(特别是字段多时)
复用性差(相同映射需重复编写)
2. ResultMap 显式映射
核心思想:通过
<resultMap>
标签明确定义数据库字段与 Java 属性的映射关系<!-- 1. 声明结果映射 --> <resultMap id="baseMap" type="com.example.mybatis.model.UserInfo"><!-- 主键字段映射 --><id property="id" column="id"/><!-- 普通字段映射 --><result property="username" column="username"/><result property="password" column="password"/><result property="age" column="age"/><!-- 处理命名不一致的字段 --><result property="deleteFlag" column="delete_flag"/><result property="createTime" column="create_time"/><result property="updateTime" column="update_time"/> </resultMap><!-- 2. 使用结果映射 --> <select id="selectAll2" resultMap="baseMap">SELECT * FROM user_info <!-- 无需字段别名 --> </select>
关键特性:
<id>
:用于主键字段,提升性能并支持对象识别
<result>
:定义普通字段映射
property
:Java 实体类属性名(驼峰式)
column
:数据库字段名(蛇形命名)优点:
映射关系清晰可见
可复用(多个查询可引用同一个
<resultMap>
)支持复杂映射(嵌套对象、集合等)
缺点:
配置稍显繁琐(需额外声明映射关系)
3. 全局驼峰命名转换
核心思想:开启 MyBatis 全局配置,自动将蛇形命名转为驼峰命名
配置方式(二选一):
1. 在
.xml
中启用:<configuration><settings><!-- 开启驼峰命名自动映射 --><setting name="mapUnderscoreToCamelCase" value="true"/></settings> </configuration>
2. Spring Boot 配置(application.yml):
mybatis:configuration:map-underscore-to-camel-case: true
自动转换规则:
数据库字段名 Java 属性名 转换说明 delete_flag
deleteFlag
下划线后字母大写 create_time
createTime
去除下划线并驼峰化 update_time
updateTime
同上 优点:
零编码映射(无需别名/ResultMap)
保持 SQL 简洁
一劳永逸(全局生效)
缺点:
无法自定义特殊字段映射
对非标准命名支持有限
2.1.4.2增
Mapper层:
Integer insertUser(UserInfo userInfo);Integer insertUser2(@Param("userInfo") UserInfo userInfo);
XML:
<insert id="insertUser">insert into user_info (username, `password`, age)values(#{username}, #{password}, #{age})</insert><insert id="insertUser2" useGeneratedKeys="true" keyProperty="userInfo.id">insert into user_info (username, `password`, age)values(#{userInfo.username}, #{userInfo.password}, #{userInfo.age})</insert>
测试代码:
@Testvoid insertUser() {UserInfo userInfo = new UserInfo();userInfo.setUsername("u6");userInfo.setPassword("p4444");userInfo.setAge(10);userInfoMapperXML.insertUser(userInfo);System.out.println(userInfo.getId());}@Testvoid insertUser2() {UserInfo userInfo = new UserInfo();userInfo.setUsername("u8");userInfo.setPassword("p6666");userInfo.setAge(13);Integer result = userInfoMapperXML.insertUser2(userInfo);System.out.println("影响行数: " + result + ",自增id: " + userInfo.getId());}
方式1:直接对象参数(基础版)
无前缀访问:直接使用
#{属性名}
访问对象的属性MyBatis 处理流程:
获取方法参数对象
userInfo
通过反射读取属性值
将值注入 SQL 占位符
方式2:@Param 注解参数(高级版)
属性 作用 值说明 useGeneratedKeys
启用数据库自增主键支持 true
/false
(默认false)keyProperty
指定回填到参数的属性路径 对象.属性 (如 userInfo.id
)
带前缀访问:必须使用
#{参数名.属性}
格式@Param 作用:为参数创建命名空间
2.1.4.3改
Mapper层:
Integer updateUser(String password, Integer age, Integer id);
XML:
<update id="updateUser">update user_info set password = #{password}, age = #{age}where id = #{id}</update>
测试代码:
@Testvoid updateUser() {userInfoMapperXML.updateUser("updatePassword", 66, 13);}
运行截图:
2.1.4.4删
Mapper层:
Integer deleteUser(Integer id);
XML:
<delete id="deleteUser">delete from user_info where id = #{id}</delete>
测试代码:
@Testvoid deleteUser() {userInfoMapperXML.deleteUser(17);}
运行截图:
2.1.3常见报错及解决方案
常见的有四种报错,这里一一讲解:
🚨 2.1.3.1配置文件对应问题
报错现象:
Invalid bound statement (not found)
org.apache.ibatis.binding.BindingException
根本原因:
Mapper 接口与 XML 文件绑定失败排查步骤:
- namespace 与接口全限定名不匹配
- XML 文件存放位置错误
- MyBatis 未扫描到 XML
- SQL 语句 id 与方法名不匹配
🔍 2.1.3.2字段映射问题
报错现象:
Could not set property 'createTime'
查询结果部分字段为null
排查步骤:
- 未开启驼峰命名转换
- ResultMap 配置错误
- SQL 未返回必要字段
⚙️ 2.1.3.3参数绑定问题
报错现象:
Parameter 'xxx' not found
There is no getter for property named 'xxx'
典型场景:
// Mapper接口 List<User> selectByAge(@Param("min") Integer minAge, Integer maxAge); // 缺少@Param// XML <select id="selectByAge">SELECT * FROM user WHERE age BETWEEN #{min} AND #{maxAge} <!-- 参数名错误 --> </select>
解决方案:
单参数:可直接用
#{任意名}
多参数:必须用
@Param
注解List<User> selectByAge(@Param("min") Integer minAge,@Param("max") Integer maxAge );
对象参数:
<!-- 正确 --> #{user.age}<!-- 错误 --> #{age}
📜 2.1.3.4配置文件语法错误
报错现象:
Error parsing SQL Mapper Configuration
XML 文件加载失败
排查重点:
特殊符号未转义
标签未闭合
YAML 缩进错误
2.1.4在线diff工具
在 MyBatis 开发中,XML 配置与 Java 接口的一致性检查是高频痛点(如 namespace
不匹配、id
重复或遗漏),而人工比对效率低且易出错。此时 在线 Diff 工具 成为关键辅助手段,它能快速定位配置差异,显著提升排障效率。
常见的在线diff工具推荐:
Diffchecker
支持文本、代码、图片、PDF、Excel等文件的对比,免费且功能强大,适合代码审查和文档核对DiffNow
专为文本、XML和JSON文件设计,提供差异检测和报告生成功能,操作简单无双工具
免费在线文本diff工具,支持代码对比、翻译差异检测,界面友好且无需注册。Draftable
专注于PDF和Word文件的比对,免费账户提供300+文档模板,适合团队协作。LineDiff
简单的在线文本对比工具,适合快速查看行级差异。
优势:
痛点 | Diff 工具作用 | 传统方式缺陷 |
---|---|---|
id 与接口方法名不一致 | 秒级定位不匹配项 | 肉眼逐行比对,耗时长易遗漏 |
namespace 路径错误 | 验证接口全路径与 XML 声明一致性 | 手动复制粘贴路径易出错 |
多人协作冲突 | 快速识别版本间配置差异 | Git 差异查看不直观 |
通过自动化工具替代人工校验,开发者可更专注业务逻辑实现,减少“配置一致性”问题带来的时间损耗。
2.2其他查询操作
测试表:
-- 创建文章表
DROP TABLE IF EXISTS article_info;CREATE TABLE article_info (id INT PRIMARY KEY auto_increment,title VARCHAR ( 100 ) NOT NULL,content TEXT NOT NULL,uid INT NOT NULL,delete_flag TINYINT ( 4 ) DEFAULT 0 COMMENT '0-正常, 1-删除',create_time DATETIME DEFAULT now(),update_time DATETIME DEFAULT now()
) DEFAULT charset 'utf8mb4';-- 插入测试数据
INSERT INTO article_info ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1 );
2.2.1多表查询
这里讲解多表查询仅以一种为例:
我们用到的俩个表是两个测试代码中的表:
-
文章表(article_info):存储文章信息
-
用户表(user_info):存储作者信息
需求:根据文章ID查询文章详情同时获取作者的用户名和年龄(需要跨表查询)
Mapper:
@Mapper public interface ArticleInfoMapper {ArticleInfo selectArticleInfoById(Integer id);}
model:
@Data public class ArticleInfo {// 文章字段private Integer id;private String title;private String content;private Integer uid; // 作者ID(关联字段)private Integer deleteFlag;private Date createTime;private Date updateTime;// 用户字段(多表查询扩展)private String username; // 作者姓名private Integer age; // 作者年龄 }
设计:实体类包含跨表字段,MyBatis会自动映射同名属性
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.example.mybatis.mapper.ArticleInfoMapper"><select id="selectArticleInfoById" resultType="com.example.mybatis.model.ArticleInfo">selectta.*,tb.username,tb.agefrom article_info taleft join user_info tbon ta.uid = tb.idwhere ta.id = 1 <!-- 多表查询--></select> </mapper>
运行截图:
多表查询的三种实现方式对比:
方式 | 适用场景 | 性能影响 |
---|---|---|
JOIN查询 | 关联数据量小 | 单次查询 |
嵌套查询 | 关联数据量大 | N+1查询问题 |
子查询 | 简单过滤条件 | 可能影响性能 |
2.2.2慢sql问题
一、什么是慢SQL?
想象你在图书馆找书:
-
✅ 快查询:有精准的索书号(索引),直接找到书
-
❌ 慢查询:没有索引,只能一排排书架翻找(全表扫描)
慢SQL就是执行时间过长的数据库查询,就像在图书馆里花1小时找一本书。通常当查询超过100毫秒,就认为是慢SQL。
二、哪些场景会出现慢SQL?(常见例子)
1. 全表扫描(最典型)
-- 没有索引的查询(像没有目录的书架) SELECT * FROM users WHERE name = '小明';
➤ 现象:数据库扫描10万行才找到1条数据
2. 多表关联查询
-- 同时查3张表(像同时翻3本书找信息) SELECT * FROM orders JOIN users ON orders.user_id = users.id JOIN products ON orders.product_id = products.id;
➤ 风险:数据量指数级增长(100订单×100用户×100商品=100万组合)
3. 模糊查询
-- 开头模糊查询(像查"*结尾是明的名字") SELECT * FROM users WHERE name LIKE '%明';
4. 大数据量分页
-- 翻到第1000页(像从1000页的书里撕下最后10页) SELECT * FROM products LIMIT 10000, 10;
三、为什么慢SQL很危险?
问题类型 | 后果 | 类比 |
---|---|---|
阻塞其他操作 | 整个系统变卡顿 | 收银台排长队 |
消耗CPU资源 | 服务器负载飙升 | 引擎过热 |
磁盘IO过高 | 硬件寿命缩短 | 汽车频繁急刹车 |
用户体验差 | 页面加载转圈时间长 | 电梯反应慢 |
四、常见解决方案
✅ 方案1:创建索引
-- 给name字段加索引(像给书加目录) CREATE INDEX idx_name ON users(name);-- 查询立刻变快 SELECT * FROM users WHERE name = '小明';
✅ 方案2:减少多表查询
/* 优化前(三表关联) */ SELECT products.*, users.name FROM orders JOIN users ON orders.user_id = users.id JOIN products ON orders.product_id = products.id;/* 优化后(拆成两次简单查询) */ -- 第一步:查订单信息 SELECT product_id, user_id FROM orders WHERE ...;-- 第二步:分别查产品和用户 SELECT * FROM products WHERE id IN (100,101,102); SELECT name FROM users WHERE id IN (1,2,3);
✅ 方案3:限制返回数据量
-- 只查需要的列(不要搬整个书架) SELECT id, name FROM users; -- 代替 SELECT *-- 限制结果数量(只拿前10本书) SELECT * FROM products LIMIT 10;
✅ 方案4:避免全模糊查询
-- 改用右模糊(允许使用索引) SELECT * FROM users WHERE name LIKE '张%'; -- 全文检索方案(专业解决方案) ALTER TABLE products ADD FULLTEXT(name); SELECT * FROM products WHERE MATCH(name) AGAINST('手机');
3.小结
其实MyBatis到这里还尚未结束,但考虑文章篇幅过长,剩下一些内容如动态sql等内容将放到随后的杂谈篇进行,大家敬请期待~
另外最后的最后,欢迎大家加入我的社区哦,初创社区难免经验不足,请大家多多包涵,也欢迎大家前来多多交流。
爱吃烤鸡翅的酸菜鱼社区-CSDN社区云https://bbs.csdn.net/forums/aaa1f71356f6475db42ea9ea09a392bc?spm=1001.2014.3001.6682