最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
MyBatis XML开发全面完整指南
时间:2026-08-06 07:31:04 编辑:袖梨 来源:一聚教程网
前期回顾:
MyBatis的开发有两种方式:
1.注解
2.XML
上一小节,分享了使用注解的方式,接下来这一节将分享XML的方式。
使用MyBatis的注解方式,主要是来完成一些简单的增删改查功能,但如果需要实现复杂的SQL功能,更推荐使用XML来配置映射语句,也就是将SQL语句写在XML配置文件中
一、MyBatis XML配置文件
MyBatis XML的方式需要以下两步:
- 配置数据库链接字符串和MyBatis
- 写持久层代码
1.1 配置数据库链接字符串和MyBatis
application.yml配置:
# 数据库连接配置spring: datasource: url: jdbc:mysql://127.0.0.1:3306/mybatis_test? characterEncoding=utf8&useSSL=falseusername: rootpassword: rootdriver-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#数据库链接的urlspring.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
1.2 写持久层代码
持久层代码分为两部分:
- 方法定义:Interface
- 方法实现:XXX.xml

1.2.1 添加mapper接口
这里我们先添加一个插件:

数据持久层的定义接口:
package com.MybatisDemo.demo.mapper;import com.MybatisDemo.demo.model.UserInfo;import org.apache.ibatis.annotations.Mapper;import java.util.List;@Mapperpublic interface UserInfoXMLMapper {List<UserInfo> queryAllUser();}1.2.2 添加UserInfoXMLMapper.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">//这里的namespace根据实际情况写<mapper namespace="com.MybatisDemo.demo.mapper.UserInfoXMLMapper"></mapper>
创建UserInfoXMLMapper.xml,路径参考properties/yml中的配置

查询所有用户的具体实现:
- 光标对准queryAllUser方法名,然后alt+enter键,点击Generate statement

将自动生成:

- 在<select></select>标签中写入sql语句:
select username,`password`,age,gender,phone from user_info
- 单元测试
@SpringBootTestclass UserInfoXMLMapperTest { @Autowired private UserInfoXMLMapper userInfoXMLMapper; @Test void queryAllUser(){ List<UserInfo> userInfoXMLList =userInfoXMLMapper.queryAllUser(); System.out.println(userInfoXMLList); }}- 运行展示

以上是具体操作,接下来对标签进行说明

- <mapper>标签:需要指定 namespace 属性,表示命名空间,值为 mapper 接口的全限定名,包括全包名.类名。
- <select>查询标签:是用来执行数据库的查询操作的
—id:是和 Interface (接口)中定义的方法名称⼀样的,表示对接口的具体实现方法。
—resultType:是返回的数据类型,也就是开头我们定义的实体类.
二、增删改查操作
2.1 增(Insert)
在 MyBatis XML 中,插入操作使用 <insert> 标签。该标签的 id 属性需要与 Mapper 接口中定义的方法名保持一致。
Mapper 接口方法定义:
// 插入用户信息Integer insertUser(UserInfo userInfo);
XML 映射配置:
<insert id="insertUser"> insert into user_info (username, password, age, gender, phone) values (#{username}, #{password}, #{age}, #{gender}, #{phone})</insert>测试方法:
@Test void insertUser() { UserInfo user = new UserInfo(); user.setUsername("hhh1"); user.setPassword("123456"); user.setAge(20); user.setGender(2); user.setPhone("1235"); Integer row = userInfoXMLMapper.insertUser(user); System.out.println("添加数据条数:" + row); }运行展示:

如果使用@Param设置参数名称,使用方法和注解类似:
//UserInfoXMLMapper接⼝:Integer insertUser(@Param("userInfo") UserInfo userInfo);//UserInfoXMLMapper.xml实现:<insert id="insertUser">insert into user_info (username, password, age, gender, phone) values(#{userInfo.username},#{userInfo.password},#{userInfo.age},#{userInfo.gender},#{userInfo.phone})</insert>返回自增id:接口定义不变,Mapper.xml实现 设置useGeneratedKeys和keyProperty属性
<insert id="insertUser" useGeneratedKeys="true" keyProperty="id"> insert into user_info (username, password, age, gender, phone) values (#{username}, #{password}, #{age}, #{gender}, #{phone})</insert>2.2 删(Delete)
删除操作使用 <delete> 标签,同样通过 id 属性与方法绑定。
Mapper 接口方法定义:
// 根据用户ID删除用户Integer deleteUser(Integer id);
XML 映射配置:
<delete id="deleteUserById"> delete from user_info where id = #{id}</delete>测试方法:
@Test void deleteUserByID() { Integer rows =userInfoXMLMapper.deleteUserByID(6); System.out.println("删除影响行数:" + rows); }运行展示:

2.3 改(Update)
更新操作使用 <update> 标签,用于修改数据库中已有的记录。
Mapper 接口方法定义:
// 根据用户ID更新用户信息Integer updateUser(UserInfo userInfo);
XML 映射配置:
<update id="updateUser"> update user_info set username = #{username} where id = #{id}</update>测试方法:
@Test void updateUser() { UserInfo user = new UserInfo(); user.setId(1); user.setUsername("h1"); Integer rows = userInfoXMLMapper.updateUser(user); System.out.println("修改行数:" + rows); }运行展示:

2.4 查(Select)
查询操作使用<sekect>标签,这在上一节已初步接触。这里补充更详细的用法和参数传递。
Mapper 接口方法定义(带参数查询):
// 根据用户名查询用户UserInfo selectUserByName(String username);
XML 映射配置:
<select id="select"> select id, username, password, age, gender, phone, delete_flag, create_time, update_time from user_info</select>
运行展示:

解决方法和类注解类似:
1.起别名
2.结果映射
3.开启驼峰命名
其中1,3的解决方法和注解一样,感兴趣的可以看上一篇文章,接下来介绍xml中的结果映射
<resultMap id="BaseMap" type="com.MybatisDemo.demo.model.UserInfo"> <id column="id" property="id"></id> <result column="delete_flag" property="deleteFlag"></result> <result column="create_time" property="createTime"></result> <result column="update_time" property="updateTime"></result></resultMap><select id="queryAllUser" resultMap="BaseMap">select id, username,password, age, gender, phone, delete_flag, create_time, update_time from user_info</select>
通过 XML 配置 SQL,使得 SQL 语句与 Java 代码分离,结构更清晰,尤其便于维护复杂的动态 SQL
三、其他查询操作
3.1 多表查询
多表查询和单表查询类似,只是sql不同而已
数据准备:
DROP TABLE IF EXISTS articleinfo;CREATE TABLE articleinfo ( 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 articleinfo ( title, content, uid ) VALUES ( 'Java', 'Java正文', 1);
数据查询 需求: 根据uid查询作者的名称等相关信息:
select ta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender from articleinfo ta left join user_info tb on ta.uid = tb.id where ta.id =1
对应model:
@Datapublic class ArticleInfo { private Integer id; private String title; private String content; private Integer uid; private Integer deleteFlag; private Date createTime; private Date updateTime; //⽤⼾相关信息 private String username; private Integer age; private Integer gender;}接口定义:
@Mapperpublic interface ArticleInfoMapper { @Select("SELECT ta.id,ta.title,ta.content,ta.uid,tb.username,tb.age,tb.gender " + "FROM articleinfo ta LEFT JOIN user_info tb ON ta.uid = tb.id " + "WHERE ta.id = #{id}") ArticleInfo queryUserByUid(Integer id);}3.2 #{} 和 ${}
3.2.1 #{} 和 ${} 使用
- 先看Interger类型的参数
#{} 的使用示例:
@Select("select username, password, age, gender, phone from user_info where id = #{id}") UserInfo queryById(Integer id);
我们发现我们输入的参数并没有在后面拼接,id值使用 ?进行占位,这中sql我们称为“预编译sql”
${} 的使用示例:
@Select("select username, password, age, gender, phone from user_info where id = ${id}") UserInfo queryById(Integer id);
- 看String类型的参数
#{} 的使用示例:
@Select("select username, password, age, gender, phone from user_info where username = #{name}") UserInfo queryByname(String name);
${} 的使用示例:
@Select("select username, password, age, gender, phone from user_info where username = ${name}") UserInfo queryByname(String name);
可以看到,这次参数依然是直接拼接在sql语句中了,但是字符串作为参数,需要添加单引号,使用${ }不会拼接引号,导致程序报错
修改代码为:
@Select("select username, password, age, gender, phone from user_info where username = '${name}'") UserInfo queryByname(String name);
从上面例子可以看出:
#{} 使用的是预编译SQL, 通过 ? 占位的⽅式, 提前对SQL进行编译, 然后把参数填充到SQL语句中. #{} 会根据参数类型, ⾃动拼接引号 '' . ${} 会直接进行字符替换, ⼀起对SQL进行编译. 如果参数为字符串, 需要加上引号 '' . 参数为数字类型时, 也可以加上, 查询结果不变, 但是可能会导致索引失效, 性能下降.
3.2.2 #{} 和 ${} 区别
- 处理方式不同:#{} 采用预编译处理,而 ${} 是字符串直接替换。
- 安全性差异:#{} 可以有效防止 SQL 注入攻击,而 ${} 存在 SQL 注入的风险。在查询语句中,虽然可以使用 ${},但通常推荐使用 #{}。
- 适用场景:在某些特定场景下,#{} 无法满足需求,例如:
- 排序功能(ORDER BY 子句)
- 表名作为参数时
- 字段名作为参数时
- 模糊查询处理:虽然 ${} 可以完成模糊查询,但由于存在 SQL 注入风险,通常建议使用 MySQL 内置的 CONCAT() 函数配合 #{} 来实现:
<!-- 安全的模糊查询写法 --><select id="selectUserByName" resultType="UserInfo"> SELECT * FROM user_info WHERE username LIKE CONCAT('%', #{name}, '%')</select>总结:在大多数情况下,应优先使用 #{} 以确保安全性;只有在需要动态指定表名、字段名或排序方式等特殊场景下,才考虑使用 ${},并确保参数来源可信。
3.3 排序功能
在 MyBatis 中实现动态排序功能时,由于 #{} 会对参数进行预编译处理并添加引号,导致 SQL 语句语法错误,因此需要使用 ${} 来实现。
Mapper 接口方法定义:
// 根据指定字段排序查询用户列表List<UserInfo> selectUsersOrderBy(@Param("orderField") String orderField, @Param("orderType") String orderType);XML 映射配置:
<select id="selectUsersOrderBy" resultType="UserInfo"> SELECT * FROM user_info ORDER BY ${orderField} ${orderType}</select>测试方法:
@Testvoid testSelectUsersOrderBy() { // 按年龄降序排列 List<UserInfo> users = userInfoXMLMapper.selectUsersOrderBy("age", "DESC"); users.forEach(System.out::println);// 按创建时间升序排列List<UserInfo> users2 = userInfoXMLMapper.selectUsersOrderBy("create_time", "ASC");users2.forEach(System.out::println);}安全注意事项:
- 使用
${}时,必须确保参数值来自可信来源,避免用户直接输入 - 可以在业务层对排序字段和排序类型进行白名单验证
- 建议提供固定的排序选项供用户选择,而不是完全开放输入
3.4 like查询
在 MyBatis 中进行模糊查询时,虽然可以使用 ${},但由于安全考虑,推荐使用 #{} 配合 MySQL 的 CONCAT() 函数来实现。
Mapper 接口方法定义:
// 根据用户名模糊查询List<UserInfo> selectUsersLikeName(@Param("keyword") String keyword);XML 映射配置(安全写法):
<select id="selectUsersLikeName" resultType="UserInfo"> SELECT * FROM user_info WHERE username LIKE CONCAT('%', #{keyword}, '%')</select>XML 映射配置(不安全写法 - 不推荐):
<!-- 存在 SQL 注入风险,不推荐使用 --><select id="selectUsersLikeName" resultType="UserInfo"> SELECT * FROM user_info WHERE username LIKE '%${keyword}%'</select>测试方法:
@Testvoid testSelectUsersLikeName() { // 查询包含"张"字的用户 List<UserInfo> users = userInfoXMLMapper.selectUsersLikeName("张"); System.out.println("查询结果数量:" + users.size()); users.forEach(System.out::println);// 查询包含"admin"的用户List<UserInfo> users2 = userInfoXMLMapper.selectUsersLikeName("admin");System.out.println("查询结果数量:" + users2.size());}其他模糊查询模式:
- 左模糊:
LIKE CONCAT('%', #{keyword}) - 右模糊:
LIKE CONCAT(#{keyword}, '%') - 全模糊:
LIKE CONCAT('%', #{keyword}, '%')(如上例)
性能优化建议:
- 对于大数据表的模糊查询,建议添加合适的索引
- 避免在模糊查询条件前使用通配符
%,这会导致索引失效 - 考虑使用全文索引(FULLTEXT)替代 LIKE 查询,提高查询效率
四、数据库连接池
4.1 介绍
数据库连接池(Database Connection Pool)是一种用于管理数据库连接的技术,它在应用程序启动时创建一定数量的数据库连接,并将这些连接保存在一个"池"中。当应用程序需要访问数据库时,从连接池中获取一个空闲连接,使用完毕后归还给连接池,而不是直接关闭连接。
数据库连接池的主要优势:
- 提高性能:避免了频繁创建和销毁连接的开销
- 资源复用:连接可以被多个请求重复使用
- 连接管理:可以控制连接数量,防止数据库过载
- 超时处理:自动回收空闲连接,避免连接泄漏
常见的数据库连接池实现:
- Hikari(黑卡里):Spring Boot 2.x 默认连接池,性能优异
- Druid(德鲁一):阿里巴巴开源,功能全面,监控完善
- Tomcat JDBC Pool:Tomcat 内置连接池
- C3P0:老牌连接池,稳定性好
4.2 使用
- Hikari:SpringBoot默认数据库连接池

- Druid:如果我们想把默认的数据库连接池切换为Druid数据库连接池,只需要引入相关依赖即可
<dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-3-starter</artifactId> <version>1.2.21</version></dependency>//如果SpringBoot版本为2.X, 使⽤druid-spring-boot-starter 依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.17</version></dependency>
五、小结
家人们,因为我前几天回了趟家,所以断更了几天,今天预计更新两篇哦。我这次回家,买的榴莲超级漂亮,而且家里水果店19.9一斤,武汉要25.9一斤,我应该从家里提一个过来的。失算了,现在有点痛苦,但是我找到实习了,所以我决定上两天班了再买,哈哈哈哈。