目录
4.MyBatis XML 配置文件
4.1 配置连接字符串和 MyBatis
4.2 写持久层代码
4.2.1 添加 mapper 接口
4.2.2 添加 UserInfoXMLMapper.xml
4.2.3 单元测试
4.3 增删改查操作
4.3.1 查(Select)
1.起别名
2.结果映射:ResultMap 标签
后续补充:
3.配置驼峰自动转换(推荐)
4.3.2 增(Insert)
返回自增 id
4.3.3 改(Update)
4.3.4 删(Delete)
书接上文:Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)~~
4.MyBatis XML 配置文件
Mybatis 的开发有两种方式: 1. 注解 2. XML 上面学习了注解的方式, 接下来我们学习 XML 的方式 使用 Mybatis 的注解方式,主要是来完成一些简单的增删改查功能. 如果需要实现复杂的 SQL 功能,建议使用XML来配置映射语句,也就是将 SQL 语句写在 XML 配置文件中. MyBatis XML 的方式需要以下两步: 1. 配置数据库连接字符串和MyBatis 2. 写持久层代码
闲聊:注解和 XML 是可以共存的,甚至可以共存在一个类里,只不过但是不建议这么写,就好像上身穿了西装,下身穿了牛仔裤,就不是很搭~~
对比 XML 和 注解 的步骤👇
| XML步骤 | 注解步骤 |
| 1.添加依赖:mybatis-starter、mysql | 1.添加依赖 |
| 2.配置数据库信息 | 2.配置数据库信息 |
| 3.定义接口 | 3.定义接口 |
| 4.使用 XML 实现接口 | 4.使用 注解 实现接口 |
前两步都是一样的,我们目前都配置完了,我们接下来新建一个类 UserInfoMapperXML 来学习这里的知识~~
4.1 配置连接字符串和 MyBatis
此步骤需要进行两项设置,数据库连接字符串设置和 MyBatis 的 XML 文件配置
我们工作中会有很多的代码和不同的文件,那么 MyBatis 怎么知道这个 xml 文件放在哪了?那么我就需要做两件事:
1.告诉 MyBatis 我放在哪了
2.告诉 MyBatis 我到底要实现哪个接口
这就需要新增一个配置信息👇
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
其中 ** 表示通配符,表示 匹配多个字母~~
写成 **.xml 时:这个路径下的所有 xml 都会加载(写成 *.xml 也是一样的效果)
如果是 application.yml 文件, 配置内容如下:
# 数据库连接配置
spring:
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: root
driver-class-name: com.mysql.cj.jdbc.Driver
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mybatis:
mapper-locations: classpath:mapper/**Mapper.xml
如果是application.properties文件, 配置内容如下:
#驱动类名称
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
#数据库连接的url
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
#连接数据库的用户名
spring.datasource.username=root
#连接数据库的密码
spring.datasource.password=root
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mybatis.mapper-locations=classpath:mapper/**Mapper.xml
4.2 写持久层代码
持久层代码分两部分 1. 方法定义 Interface 2. 方法实现: XXX.xml 
4.2.1 添加 mapper 接口
数据持久层的接口定义:
package com.bit.mybatis.mapper;
import com.bit.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: CoderYanger
* Date: 2026-11-07
* Time: 17:33
*/
@Mapper
public interface UserInfoMapperXML {
List<UserInfo> selectAll();
}
4.2.2 添加 UserInfoXMLMapper.xml
数据持久成的实现,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.demo.mapper.UserInfoMapper">
</mapper>
com.bit.mybatis.mapper.UserInfoMapperXML 表示你实现的是哪个接口,这一部分按住 Ctrl 可以直接跳转的~~
闲聊:感兴趣的同学可以安装一下下面的插件~~


创建 UserInfoXMLMapper.xml, 路径参考 yml 中的配置
查询所有用户的具体实现 :
<?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.bit.mybatis.mapper.UserInfoMapperXML">
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
</select>
</mapper>
以下是对以上标签的说明: • <mapper> 标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接口的全限定 名,包括全包名.类名。 • <select> 查询标签:是用来执行数据库的查询操作的: ◦ id :是和 Interface (接口)中定义的方法名称一样的,表示对接口的具体实现方法。 ◦ resultType :是返回的数据类型,也就是开头我们定义的实体类.
4.2.3 单元测试
package com.bit.mybatis.mapper;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import static org.junit.jupiter.api.Assertions.*;
/**
* Created with IntelliJ IDEA.
* Description:
* User: CoderYanger
* Date: 2026-11-07
* Time: 18:22
*/
@SpringBootTest
class UserInfoMapperXMLTest {
@Autowired
private UserInfoMapperXML userInfoMapperXML;
@Test
void selectAll() {
userInfoMapperXML.selectAll().stream().forEach(x-> System.out.println(x));
}
}
运行结果如下:
注意,这其中的对应关系👇
如果没有按照这个顺序规则来写的话就会出现问题
第一个出错:没有映射上,把 mapper 改为 mapper1(改掉 **Mapper.xml 也是一样的)👇
# 配置 mybatis xml 的文件路径,在 resources/mapper 创建所有表的 xml 文件
mapper-locations: classpath:mapper1/**Mapper.xml
报错结果显示:绑定异常,没找到👇
第二个出错:把 selectAll 改为 selectAll1,与原本的 selectAll 对应不上
<?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.bit.mybatis.mapper.UserInfoMapperXML">
<select id="selectAll1" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
</select>
</mapper>
@Mapper
public interface UserInfoMapperXML {
List<UserInfo> selectAll();
}
我们发现报的错误信息依旧是这个👇
如果说上面的 com.bit.mybatis.mapper.UserInfoMapperXML 对应不上了,把 XML 去掉,再加个 1
<?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.bit.mybatis.mapper.UserInfoMapper1">
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
</select>
</mapper>
发现依旧是 绑定异常👇
所以当看到这个异常就按照上面图片的对应关系去查就可以了~~
4.3 增删改查操作
接下来,我们来实现一下用户的增加、删除和修改的操作.
方法的声明都跟注解是一样的~~
4.3.1 查(Select)
闲聊:传递一个参数、传递多个参数,跟我们的注解是一模一样的,此处就不再给大家赘述了~~
只是写法不一样,我们注解是把 SQL 语句放到了注解里面,XML 是放到标签里面了~~
同样的, 使用XML 的方式进行查询, 也存在数据封装的问题 我们把SQL语句进行简单修改, 查询更多的字段内容
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
</select>
运行结果:
结果显示: deleteFlag, createTime, updateTime 也没有进行赋值,跟注解一样,数据库的字段名和我们的属性如果是一致的话,就直接给映射上了,但是不一致的话,他不知道怎么去映射,解决办法和注解类似: 1. 起别名 2. 结果映射 3. 开启驼峰命名
1.起别名
UserInfoMapper.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.bit.mybatis.mapper.UserInfoMapperXML">
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
<!– select * from user_info–>
select id,username,`password`,age,gender,phone,
delete_flag as deleteFlag,
create_time as createTime,
update_time as updateTime
from user_info
</select>
</mapper>
运行结果👇可行的
2.结果映射:ResultMap 标签
注解方式是写注解,但是 XML 里面没办法写注解,接下来看下 xml 如果来写结果映射 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.bit.mybatis.mapper.UserInfoMapperXML">
<resultMap id="BaseMap" type="com.bit.mybatis.model.UserInfo">
<id property="id" column="id"></id>
<result property="deleteFlag" column="delete_flag"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
</resultMap>
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
<!– select id,username,`password`,age,gender,phone,–>
<!– delete_flag as deleteFlag,–>
<!– create_time as createTime,–>
<!– update_time as updateTime–>
<!– from user_info–>
</select>
<select id="selectAll2" resultMap="BaseMap">
select * from user_info
</select>
</mapper>
其实跟注解方式是基本一样的👇

后续补充:
使用的时候直接映射就可以了👇
虽然这里只写了三个就能达到我们的目的👇
<result property="deleteFlag" column="delete_flag"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
但是还是建议写全👇把其他的都补上
@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;
}
如果没写全的话,别人调用的时候,其他的值就可能映射不上~~
有人可能会觉得麻烦,还要写全,其实我们在最后会教大家一个其他的方式,可以不用写这些代码的~~
package com.bit.mybatis.mapper;
import com.bit.mybatis.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
/**
* Created with IntelliJ IDEA.
* Description:
* User: CoderYanger
* Date: 2026-11-07
* Time: 17:33
*/
@Mapper
public interface UserInfoMapperXML {
List<UserInfo> selectAll();
List<UserInfo> selectAll2();
}
@Test
void selectAll2() {
userInfoMapperXML.selectAll().stream().forEach(x-> System.out.println(x));
}
来看运行结果👇
3.配置驼峰自动转换(推荐)
跟注解方式一样,可参考👇
Java EE 进阶:8.MyBatis 操作数据库(入门)(第二弹)
闲聊:开发中使用注解还是XML的方式? 关于开发中使用哪种模式这个问题, 没有明确答案. 仁者见仁智者见智, 并没有统一的标准, 更多是取决于你的团队或者项目经理, 项目负责人.
4.3.2 增(Insert)
依旧 Alt+Enter 键自动生成👇
从这里我们也能看出区别👇insert 没有 resultType 或者 resultMap,其实是只有 select 有,其他的都不用添加,我们的 insert、update、delete 返回的都是数字类型,所以不用加上 resultType

闲聊:其实方法定义的时候也是有一定规范的,插件也会根据你方法的名称大致判断出是什么,比如当你只写 user 的时候,生成时就会问你是增删改查哪一种👇

注意,是前缀,并不是说必须叫这个方法~~
UserInfoMapper接口:
Integer insertUser(UserInfo userInfo);
UserInfoMapper.xml实现:
直接从之前的地方复制粘贴过来了,从这一点也可以发现这个注解 和 我们 XML 的 SQL 是一样的👇
<insert id="insertUser">
insert into user_info (username,`password`,age) values (#{username},#{password},#{age})
</insert>
Insert 时也涉及一个传参问题,我们现在是放在对象 UserInfo 里面了,那么接下来我就要从这个对象获取到参数了,我们的传参方式,XML 和 注解是一模一样的,我们注解如何获得参数的,我们 XML 也如何获得参数~~
闲聊:因为注解是在 XML 之后才兴起的,是参考 XML 而进行设计的~~
需要注意的是我们依然要区分字段名称和属性名称~~
我们下面进行测试👇
@Test
void insertUser() {
UserInfo userInfo=new UserInfo();
userInfo.setUsername("username4");
userInfo.setPassword("password4");
userInfo.setAge(5);
userInfoMapperXML.insertUser(userInfo);
}
运行前数据库👇
运行后👇
我们发现插入成功了👇
如果使用@Param设置参数名称的话, 使用方法和注解类似 UserInfoMapper 接口:
Integer insertUser2(@Param("userInfo") UserInfo userInfo);
UserInfoMapper.xml 实现:
注意,进行参数绑定之后,跟我们之前学习注解的方式相同,不加 @Param 是可以直接使用属性名称的,但是加上 @Param 就需要在前面加上 userinfo. 了
<insert id="insertUser2">
insert into user_info (username,`password`,age)
values (#{userinfo.username},#{userinfo.password},#{userinfo.age})
</insert>
下面进行测试👇
@Test
void insertUser2() {
UserInfo userInfo=new UserInfo();
userInfo.setUsername("username5");
userInfo.setPassword("password5");
userInfo.setAge(6);
userInfoMapperXML.insertUser2(userInfo);
}
我们发现出错了👇
这次的参数绑定错误跟之前的不一样,不要光看参数绑定出错就觉得是一样的,后面的也要看!它说是 userinfo 没找到,我们对比观察发现下面代码中全是 小写的 i,应该改为大写的 I👇
<insert id="insertUser2">
insert into user_info (username,`password`,age)
values (#{userInfo.username},#{userInfo.password},#{userInfo.age})
</insert>
再来运行👇
发现此时就插入成功了👇
闲聊:如果不知道自己错哪里了,可以去用在线的 diff 工具👇
能够快速找到肉眼看不出的 Bug,比如半角逗号和全角逗号👇
或者找到空格或者 Tab 键👇
这些非常适合初学者,在网上随便找一找 在线 diff 工具 就能用~~
另外给大家说一个很多人就会犯错的点,就是空格不能省,比如说我把这个空格去掉了👇
那么拼接的时候就会直接拼接成:insert intouser_info ……,我们来看看对应的报错信息👇

我们发现它报的是一个 SQL 语法错误,mybatis_test.intouser_info 这个表不存在~~
出现这个错误的时候,如果我们肉眼就是看不出来,那就放在这里执行一下👇
如果这里能够运行成功,那么 SQL 语句绝对没问题,这时候再去排查别的错误~~
返回自增 id
和注解也是非常类似的
接口定义不变, Mapper.xml 实现 设置 useGeneratedKeys 和 keyProperty 属性
<insert id="insertUser2" useGeneratedKeys="true" keyProperty="id">
insert into user_info (username,`password`,age)
values (#{userInfo.username},#{userInfo.password},#{userInfo.age})
</insert>
对比注解的方式👇我们发现是非常相似的
@Options(useGeneratedKeys = true,keyProperty = "id")
@Insert("insert into user_info (username,`password`,age) "+
"values (#{userInfo.username},#{userInfo.password},#{userInfo.age})")
Integer insertUser2(@Param("userInfo") UserInfo userInfo);
下面我们来运行尝试拿到它的值👇
@Test
void insertUser2() {
UserInfo userInfo=new UserInfo();
userInfo.setUsername("username6");
userInfo.setPassword("password6");
userInfo.setAge(7);
Integer result=userInfoMapperXML.insertUser2(userInfo);
System.out.println("影响行数:"+result+",自增id:"+userInfo.getId());
}
运行前数据库👇
运行后👇

此时已经自增成功了~~
4.3.3 改(Update)
UserInfoMapper接口:
//我们换一种传参方式,之前是根据对象,这次使用这种方式,根据id更新
Integer updateUser(String password,Integer age,Integer id);
UserInfoMapper.xml实现:
<update id="updateUser">
update user_info set password = #{password},age = #{age}
where id =#{id}
</update>
下面来测试👇
@Test
void updateUser() {
//更新id为13的数据
userInfoMapperXML.updateUser("updatePassword5",8,13);
}
更新前:
更新后:
我们发现更新成功👇
4.3.4 删(Delete)
UserInfoMapper接口:
//根据id删除
Integer deleteUser(Integer id);
UserInfoMapper.xml实现:
<delete id="deleteUser">
delete from user_info where id = #{id}
</delete>
下面测试👇
@Test
void deleteUser() {
//把刚刚更新的id为13的数据删除
userInfoMapperXML.deleteUser(13);
}
删除前:
删除后:
我们发现删除成功👇
闲聊:我们会发现当我们学习完 MyBatis 的注解操作之后再来学习 MyBatis 的 XML 操作就会简单很多~~
答疑:这个部分的 id 有啥用??👇
这个不是必须要加的~~
爱加不加,放在这就是表示主键,其他的都是普通键,如果你的主键是一样的,那你删了也行~~
我们删了之后也是正常走的👇
<?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.bit.mybatis.mapper.UserInfoMapperXML">
<resultMap id="BaseMap" type="com.bit.mybatis.model.UserInfo">
<!– <id property="id" column="id"></id>–>
<result property="deleteFlag" column="delete_flag"></result>
<result property="createTime" column="create_time"></result>
<result property="updateTime" column="update_time"></result>
</resultMap>
<select id="selectAll" resultType="com.bit.mybatis.model.UserInfo">
select * from user_info
<!– select id,username,`password`,age,gender,phone,–>
<!– delete_flag as deleteFlag,–>
<!– create_time as createTime,–>
<!– update_time as updateTime–>
<!– from user_info–>
</select>
依旧是有的👇

