前期回顾:
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=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
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;
@mapper
public 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
- 单元测试
@springboottest
class 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:
@data
public 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;
}接口定义:
@mapper
public 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);
从上面例子可以看出:
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>测试方法:
@test
void 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>测试方法:
@test
void 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一斤,我应该从家里提一个过来的。失算了,现在有点痛苦,但是我找到实习了,所以我决定上两天班了再买,哈哈哈哈。
到此这篇关于mybatis xml开发全面完整指南的文章就介绍到这了,更多相关mybatis xml开发内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论