跳到主要内容
Spring Boot 集成 MyBatis 与 MyBatis-Plus 实战指南 | 极客日志
Java java
Spring Boot 集成 MyBatis 与 MyBatis-Plus 实战指南 深入解析持久层框架在 Java 开发中的核心作用,涵盖 MyBatis 的配置、注解与 XML 映射方式、动态 SQL 编写及参数占位符安全性对比。同时介绍 MyBatis-Plus 如何通过通用 CRUD 和条件构造器简化开发流程,提供从基础原理到进阶实战的完整技术路径,助力构建高效稳定的数据访问层。
LinuxPan 发布于 2026/3/28 更新于 2026/4/24 1 浏览持久层框架概述
持久层框架位于应用程序和数据库之间,主要负责处理数据的持久化操作。简单来说,它负责将应用中的数据以持久的方式存储到数据库,并在需要时检索出来供业务使用。
例如在电商系统中,用户信息(姓名、地址、购买记录等)需要被保存,持久层框架就负责高效、准确地完成这些存储和检索工作。
核心作用
1. 对象关系映射 (ORM)
持久层框架可以将面向对象语言中的对象与关系型数据库表进行映射。比如在 Java 中,一个 User 类包含 id、name 等属性,通过框架(如 Hibernate 或 MyBatis)可自动映射到数据库的 user 表。当创建 User 对象并保存时,框架会自动将属性值插入对应列。
它还支持复杂对象关系,比如一对多或多对多。以博客系统为例,文章 (Article) 可以有多个评论 (Comment),框架能协助在数据库中正确存储和检索这种关联数据。
2. 数据存储与检索
提供了封装好的 SQL 操作方法,简化了传统的 JDBC 流程。开发者可以通过 XML 映射文件或注解编写 SQL,然后通过接口方法调用执行。查询结果也能自动转换为可直接使用的对象列表。
3. 数据库访问抽象
不同数据库(MySQL、Oracle 等)的 SQL 语法存在差异。持久层框架可以屏蔽这些差异,更换数据库时只需修改少量配置,无需重写大量访问代码。同时提供统一的 API,使代码更清晰易读。
4. 性能优化
许多框架内置缓存机制。例如 MyBatis 的二级缓存可在 Mapper 级别缓存查询结果,减少数据库交互次数,提升高并发场景下的访问速度。此外,批量操作优化也是常见特性,通过拼接 SQL 或利用数据库特性减少交互次数。
MyBatis 基础配置
MyBatis 是一个支持自定义 SQL、存储过程及高级映射的持久层框架。它在 Java 应用和数据库间架起桥梁,既简化了操作复杂性,又保留了开发者对 SQL 的掌控力。
Maven 依赖与配置
首先需要在项目中引入相关依赖。配置文件通常位于 application.yml 或 application.properties 中。
spring:
application:
name: Test-Book-Management
datasource:
url: jdbc:mysql://127.0.0.1:3306/mybatis_test?characterEncoding=utf8&useSSL=false
username: root
password: root
mybatis:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
map-underscore-to-camel-case: true
mapper-locations:
classpath:mapper/**Mapper.xml
开启日志后,控制台会直接打印执行的 SQL 语句,便于排查问题。
MyBatis 注解开发模式 对于简单的 CRUD 操作,直接使用注解可以减少 XML 文件的维护成本。
@Select 注解 用于定义查询语句。将 SQL 与方法关联,调用方法时执行查询。
public interface UserMapper {
@Select("SELECT * FROM users")
List<User> getAllUsers () ;
}
@Update 注解 public interface UserMapper {
@Update("UPDATE users SET password = #{newPassword} WHERE id = #{id}")
int updateUserPassword (@Param("id") int id, @Param("newPassword") String newPassword) ;
}
@Delete 注解 public interface UserMapper {
@Delete("DELETE FROM users WHERE id = #{id}")
int deleteUserById (int id) ;
}
@Insert 注解 public interface UserMapper {
@Insert("INSERT INTO users (username, password) VALUES (#{username}, #{password})")
int insertUser (String username, String password) ;
}
MyBatis XML 配置文件 对于复杂查询或需要更多控制的场景,XML 映射文件是更好的选择。
接口与命名空间 首先在 Mapper 层定义接口,并添加 @Mapper 注解。
import com.example.demo.model.UserInfo;
import org.apache.ibatis.annotations.Mapper;
import java.util.List;
@Mapper
public interface UserInfoMapper {
List<UserInfo> queryAllUser () ;
}
对应的 XML 文件需遵循固定格式,关键是 namespace 属性必须与接口全限定名一致。
<?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" >
<select id ="queryAllUser" resultType ="com.example.demo.model.UserInfo" >
select username, `password`, age, gender, phone from user_info
</select >
</mapper >
增删改查 XML 示例
<insert id ="insertUser" >
insert into userinfo (username, `password`, age, gender, phone)
values (#{username}, #{password}, #{age}, #{gender}, #{phone})
</insert >
<delete id ="deleteUser" >
delete from user_info where id = #{id}
</delete >
<update id ="updateUser" >
update user_info set username=#{username} where id=#{id}
</update >
若未配置自动驼峰转换,可使用 <resultMap> 手动映射字段与属性。
<resultMap type ="org.example.model.ArticleInfo" id ="BaseMap" >
<result column ="delete_flag" property ="deleteFlag" > </result >
<result column ="create_time" property ="createTime" > </result >
<result column ="update_time" property ="updateTime" > </result >
</resultMap >
<select id ="selectArticle" resultMap ="BaseMap" >
select id,title,content,uid,delete_flag,create_time,update_time from article_info
</select >
#{} 和 ${} 的区别 这是 MyBatis 中最容易混淆的两个占位符,理解它们的原理对安全性至关重要。
#{}:预编译参数占位符 原理 :MyBatis 会将 SQL 发送给数据库进行预编译,实际参数值通过安全方式设置。生成的 SQL 类似 where id = ?。
优势 :有效防止 SQL 注入攻击。
场景 :适用于绝大多数参数传递场景,尤其是涉及用户输入时。
${}:字符串替换占位符 原理 :直接将表达式替换为实际值,不进行预编译。例如 SELECT * FROM ${tableName} 会被替换为 SELECT * FROM users。
风险 :存在 SQL 注入风险,且不会自动添加引号。
场景 :仅用于动态表名、动态列名等无法预编译的场景,需谨慎使用。
总结 :优先使用 #{} 保证安全;仅在确定无注入风险且必须动态替换非参数部分时才考虑 ${}。
动态 SQL 传统 SQL 结构固定,面对复杂条件组合时往往冗余严重。MyBatis 的动态 SQL 允许根据条件拼接片段。
<if> 标签 <insert >
INSERT INTO userinfo (username, `password`, age,
<if test ="gender != null" > gender,</if > phone)
VALUES (#{username}, #{password}, #{age},
<if test ="gender != null" > #{gender},</if > #{phone})
</insert >
<trim> 标签 用于去除多余的前缀或后缀字符,常配合 prefix、suffix 使用。
<insert >
INSERT INTO userinfo
<trim prefix ="(" suffix =")" suffixOverrides ="," >
<if test ="username !=null" > username,</if >
<if test ="password !=null" > password,</if >
<if test ="age != null" > age,</if >
</trim >
VALUES
<trim prefix ="(" suffix =")" suffixOverrides ="," >
<if test ="username !=null" > #{username},</if >
<if test ="password !=null" > #{password},</if >
<if test ="age != null" > #{age},</if >
</trim >
</insert >
<where> 标签 自动处理 WHERE 子句,去除多余的 AND 或 OR。
<select resultType ="com.example.User" >
SELECT * FROM users
<where >
<if test ="userName!= null" > AND username LIKE #{userName}</if >
<if test ="age!= null" > AND age > #{age}</if >
</where >
</select >
<set> 标签 <update parameterType ="com.example.User" >
UPDATE users
<set >
<if test ="userName!= null" > username = #{userName},</if >
<if test ="password!= null" > password = #{password},</if >
</set >
WHERE id = #{id}
</update >
<foreach> 标签 <select resultType ="com.example.User" >
SELECT * FROM users
WHERE id IN
<foreach collection ="ids" item ="id" open ="(" close =")" separator ="," >
#{id}
</foreach >
</select >
<include> 标签 <sql id ="userBaseColumns" > id, name, age</sql >
<select resultType ="com.example.User" >
SELECT <include refid ="userBaseColumns" /> FROM users
</select >
MyBatis-Plus 增强工具 MyBatis-Plus 是 MyBatis 的增强工具,旨在简化开发过程,提高效率,同时保持灵活性。它提供了通用 CRUD、条件构造器、分页插件等功能。
BaseMapper 通用操作 MP 为每个实体类对应的 Mapper 接口提供了通用的增删改查方法,无需手动编写 SQL。
@SpringBootTest
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void insert () {
UserInfo userInfo = new UserInfo ();
userInfo.setUsername("xiaocui" );
userInfo.setPassword("123456" );
userInfo.setAge(18 );
userInfoMapper.insert(userInfo);
}
@Test
void update () {
UserInfo userInfo = new UserInfo ();
userInfo.setId(11 );
userInfo.setUsername("cui" );
userInfoMapper.updateById(userInfo);
}
@Test
void delete () {
UserInfo userInfo = new UserInfo ();
userInfo.setId(11 );
userInfoMapper.deleteById(userInfo);
}
@Test
void select () {
UserInfo userInfo = userInfoMapper.selectById(8 );
System.out.println(userInfo);
}
}
常用注解
@TableName: 标识实体类对应的表。
@TableField: 绑定字段名。
@TableId: 标识主键。
@Data
@TableName("user_info")
public class Userinfo {
@TableId("id")
private Integer id;
private String username;
private String password;
private Integer age;
private Integer gender;
private String phone;
@TableField("delete_flag")
private Integer deleteflag;
private Date createTime;
private Date updateTime;
}
条件构造器 条件构造器允许通过编程方式构建复杂查询,避免硬编码 SQL。
QueryWrapper: 构造查询条件。
UpdateWrapper: 构造更新条件。
LambdaQueryWrapper: 基于 Lambda 表达式的查询,避免字段名硬编码。
LambdaUpdateWrapper: 基于 Lambda 表达式的更新。
@SpringBootTest
class UserInfoMapperTest {
@Autowired
private UserInfoMapper userInfoMapper;
@Test
void testQuery () {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper <>();
queryWrapper.select("id" ,"username" ,"password" ,"age" ,"gender" )
.eq("age" , 17 )
.like("username" , "wang" );
userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}
@Test
void testLambda () {
QueryWrapper<UserInfo> queryWrapper = new QueryWrapper <>();
queryWrapper.lambda()
.select(UserInfo::getId, UserInfo::getAge)
.eq(UserInfo::getAge, 21 )
.like(UserInfo::getUsername, "wang" );
userInfoMapper.selectList(queryWrapper).forEach(System.out::println);
}
}
条件构造器功能强大,支持排序、分组甚至子查询。结合 MP 的分页插件,能极大提升开发效率。
相关免费在线工具 Keycode 信息 查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
Escape 与 Native 编解码 JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
JavaScript / HTML 格式化 使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
JavaScript 压缩与混淆 Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
Base64 字符串编码/解码 将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
Base64 文件转换器 将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online