生命之风的低语
Whispers in the Wind of Life.

【一文搞懂】MyBatis-Plus中核心类BaseMapper的基础和进阶用法

2025-06-16 04:53:50

文章目录

基础用法进阶用法自定义SQL语句方式一:使用注解自定义SQL方法方式二:使用XML文件自定义SQL方法注解方式和XML比较:

条件构造器使用 QueryWrapper 进行查询使用 UpdateWrapper 进行更新使用 LambdaQueryWrapper 进行查询使用 LambdaUpdateWrapper 进行更新

分页查询批量操作逻辑删除乐观锁

MyBatis-Plus 核心类 BaseMapper 主要提供基本的 CRUD(创建、读取、更新、删除)操作的接口定义。它可以大大简化基于 MyBatis 的数据访问层代码的编写。源码部分如下图所示:

基础用法

可见BaseMapper 接口定义了一些基本的数据库操作方法,用法概览如下:

import com.baomidou.mybatisplus.core.conditions.Wrapper;

import com.baomidou.mybatisplus.core.metadata.IPage;

import java.io.Serializable;

import java.util.Collection;

import java.util.List;

import java.util.Map;

import org.apache.ibatis.annotations.Param;

public interface BaseMapper extends Mapper {

// 插入一条记录

int insert(T entity);

// 根据主键删除记录

int deleteById(Serializable id);

// 根据columnMap条件,删除记录

int deleteByMap(@Param("cm") Map columnMap);

// 根据条件构造器删除记录

int delete(@Param("ew") Wrapper queryWrapper);

// 根据ID列表批量删除

int deleteBatchIds(@Param("coll") Collection idList);

// 根据ID更新记录(全部字段)

int updateById(@Param("et") T entity);

// 根据条件构造器更新记录

int update(@Param("et") T entity, @Param("ew") Wrapper updateWrapper);

// 根据ID查询记录

T selectById(Serializable id);

// 根据ID列表批量查询

List selectBatchIds(@Param("coll") Collection idList);

// 根据columnMap条件查询记录

List selectByMap(@Param("cm") Map columnMap);

// 根据条件构造器查询一条记录

T selectOne(@Param("ew") Wrapper queryWrapper);

// 根据条件构造器查询记录数

Integer selectCount(@Param("ew") Wrapper queryWrapper);

// 根据条件构造器查询记录列表

List selectList(@Param("ew") Wrapper queryWrapper);

// 根据条件构造器查询全部记录,将每条记录封装为一个Map对象,List>形式。

List> selectMaps(@Param("ew") Wrapper queryWrapper);

// 根据条件构造器查询全部记录,将每条记录封装为一个Object数组,List 形式。

List selectObjs(@Param("ew") Wrapper queryWrapper);

// 分页查询,返回实体类的分页结果

> E selectPage(E page, @Param("ew") Wrapper queryWrapper);

// 分页查询,返回的Map形式的分页结果

>> E selectMapsPage(E page, @Param("ew") Wrapper queryWrapper);

}

简单应用示例: 假设User 的实体类对应数据库中的用户表,其字段包括 id、username 和 password,则可以创建一个对应的 UserMapper 接口,继承自 BaseMapper 接口,从而获得基本的 CRUD 方法的实现。

@Mapper

public interface UserMapper extends BaseMapper {

// 这里不需要编写任何方法,继承了 BaseMapper 接口后,已经包含了常用的数据库操作方法

}

然后在服务层或控制器层中注入 UserMapper并调用其方法可实现数据库操作。

@Service

public class UserService {

@Autowired

private UserMapper userMapper;

// 增加用户

public void addUser(User user) {

userMapper.insert(user);

}

// 根据用户ID查询

public User getUserById(Long userId) {

return userMapper.selectById(userId);

}

// 更新信息

public void updateUser(User user) {

userMapper.updateById(user);

}

// 删除用户

public void deleteUser(Long userId) {

userMapper.deleteById(userId);

}

}

通过上述方式可以非常方便地进行数据库操作,而不需要编写繁琐的 SQL 语句。

进阶用法

自定义SQL语句

方式一:使用注解自定义SQL方法

假设我们有一个实体类 CourseBase 和对应的 Mapper 接口,我们希望添加一个查询功能,查询所有课程名称包含指定关键字的课程。

public interface CourseBaseMapper extends BaseMapper {

// 自定义 SQL 查询:根据名称模糊查询课程

@Select("SELECT * FROM course_base WHERE name LIKE CONCAT('%', #{nameKeyword}, '%')")

List selectCoursesByName(@Param("nameKeyword") String nameKeyword);

}

方式二:使用XML文件自定义SQL方法

在 Mapper 接口中声明方法

public interface CourseBaseMapper extends BaseMapper {

List selectCoursesByStatus(String status);

}

在 resources/mapper/ 目录下创建一个名为 CourseBaseMapper.xml 的文件。这个文件与 CourseBaseMapper 接口绑定。

"http://mybatis.org/dtd/mybatis-3-mapper.dtd">

针对上述两种方式,在业务逻辑中则可调用这些自定义的方法

@Service

public class CourseService {

@Autowired

private CourseBaseMapper courseBaseMapper;

public List getCoursesByName(String nameKeyword) {

return courseBaseMapper.selectCoursesByName(nameKeyword); // 使用注解方式的方法

}

public List getCoursesByStatus(String status) {

return courseBaseMapper.selectCoursesByStatus(status); // 使用 XML 方式的方法

}

}

注解方式和XML比较:

注解 优点:简单、清晰,适合处理较为简单的 SQL 查询。 缺点:对于复杂查询,SQL 语句难以维护,可读性较差。XML 优点:适合复杂查询,SQL 语句与 Java 代码分离,易于维护和调试。 缺点:需要额外的 XML 文件,配置稍微麻烦一些。

条件构造器

MyBatis-Plus 的条件构造器(如 QueryWrapper、UpdateWrapper、LambdaQueryWrapper、LambdaUpdateWrapper 等)非常强大,可以帮助开发人员以链式编程的方式构建复杂的查询条件。

使用 QueryWrapper 进行查询

QueryWrapper 用于构建查询条件,例如多条件过滤、排序等。假设我们有一个 CourseBase 实体类和对应的 CourseBaseMapper 接口。

示例:查询课程名称包含 “Java” 并且状态为 “已发布” 的记录,按创建时间降序排序

@Service

public class CourseService {

@Autowired

private CourseBaseMapper courseBaseMapper;

public List getPublishedJavaCourses() {

QueryWrapper queryWrapper = new QueryWrapper<>();

queryWrapper.like("name", "Java") // 查询课程名称包含 "Java"

.eq("status", "已发布") // 查询状态为 "已发布"

.orderByDesc("create_date"); // 按创建时间降序排序

return courseBaseMapper.selectList(queryWrapper);

}

}

使用 UpdateWrapper 进行更新

UpdateWrapper 用于构建更新操作的条件,可以根据指定的条件更新字段。

示例:将所有课程状态为 “未发布” 的课程状态更新为 “已发布”

@Service

public class CourseService {

@Autowired

private CourseBaseMapper courseBaseMapper;

public int publishUnpublishedCourses() {

UpdateWrapper updateWrapper = new UpdateWrapper<>();

updateWrapper.eq("status", "未发布") // 条件:状态为 "未发布"

.set("status", "已发布"); // 更新状态为 "已发布"

return courseBaseMapper.update(null, updateWrapper); // 执行更新操作

}

}

使用 LambdaQueryWrapper 进行查询

LambdaQueryWrapper 是 QueryWrapper 的 lambda 表达式版本,它在属性引用上更安全(不会因为字段名拼写错误而出错),适合复杂查询。

示例:查询所有创建人是 “张三” 且课程等级为 “高级” 的记录

@Service

public class CourseService {

@Autowired

private CourseBaseMapper courseBaseMapper;

public List getAdvancedCoursesByCreator() {

LambdaQueryWrapper lambdaQueryWrapper = new LambdaQueryWrapper<>();

lambdaQueryWrapper.eq(CourseBase::getCreatePeople, "张三") // 条件:创建人为 "张三"

.eq(CourseBase::getGrade, "高级"); // 条件:课程等级为 "高级"

return courseBaseMapper.selectList(lambdaQueryWrapper);

}

}

使用 LambdaUpdateWrapper 进行更新

LambdaUpdateWrapper 是 UpdateWrapper 的 lambda 表达式版本,用于构建更新操作的条件和更新字段,保证字段名的安全性。

示例:将所有适用人群为 “学生” 的课程标签更新为 “推荐”

@Service

public class CourseService {

@Autowired

private CourseBaseMapper courseBaseMapper;

public int updateTagsForStudents() {

LambdaUpdateWrapper lambdaUpdateWrapper = new LambdaUpdateWrapper<>();

lambdaUpdateWrapper.eq(CourseBase::getUsers, "学生") // 条件:适用人群为 "学生"

.set(CourseBase::getTags, "推荐"); // 更新标签为 "推荐"

return courseBaseMapper.update(null, lambdaUpdateWrapper);

}

}

分页查询

假设现在实体类如下

@Data

@TableName("user")

public class User {

@TableId

private Long id;

private String name;

private Integer age;

private String email;

}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper {

}

创建 UserService 类,使用 UserMapper 进行分页查询

@Service

public class UserService extends ServiceImpl {

public Page getUserPage(int pageNum, int pageSize) {

Page page = new Page<>(pageNum, pageSize); // 创建分页对象

return this.baseMapper.selectPage(page, null); // 查询并返回分页结果

}

}

在控制器中调用 UserService 进行分页查询

@RestController

public class UserController {

@Autowired

private UserService userService;

@GetMapping("/users")

public Page getUsers(@RequestParam int pageNum, @RequestParam int pageSize) {

return userService.getUserPage(pageNum, pageSize);

}

}

确保Spring Boot 应用程序中配置了 MyBatis-Plus 的分页插件,以支持分页功能,可以在配置类中添加以下代码

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;

import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class MyBatisPlusConfig {

@Bean

public MybatisPlusInterceptor mybatisPlusInterceptor() {

MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();

interceptor.addInnerInterceptor(new PaginationInnerInterceptor());

return interceptor;

}

}

通过以上的配置及代码,可访问/users?pageNum=1&pageSize=10(省略了前缀),可得包含分页信息的返回结果,示例如下

{

"current": 1,

"size": 10,

"total": 100,

"records": [

{

"id": 1,

"name": "John",

"age": 25,

"email": "john@example.com"

},

// 其他用户记录...

]

}

批量操作

BaseMapper 支持批量插入、更新和删除操作,可以提高数据处理的效率。例如,批量插入可以通过 insertBatch 方法实现,批量更新可以通过 updateBatchById 方法实现,批量删除可以通过deleteBatchIds 方法实现。示例如下: 与上述案例相同,省去实体类和Mapper接口。 创建 UserService 类,使用 UserMapper 进行批量插入、更新和删除操作

@Service

public class UserService extends ServiceImpl {

// 批量插入

public void insertBatch(List userList) {

this.saveBatch(userList); // 使用 saveBatch 方法进行批量插入

}

// 批量更新

public void updateBatch(List userList) {

this.updateBatchById(userList); // 使用 updateBatchById 方法进行批量更新

}

// 批量删除

public void deleteBatch(List ids) {

this.removeByIds(ids); // 使用 removeByIds 方法进行批量删除

}

}

在控制器中调用 UserService 进行批量操作

@RestController

@RequestMapping("/users")

public class UserController {

@Autowired

private UserService userService;

// 批量插入

@PostMapping("/batch")

public void insertBatch(@RequestBody List userList) {

userService.insertBatch(userList);

}

// 批量更新

@PutMapping("/batch")

public void updateBatch(@RequestBody List userList) {

userService.updateBatch(userList);

}

// 批量删除

@DeleteMapping("/batch")

public void deleteBatch(@RequestBody List ids) {

userService.deleteBatch(ids);

}

}

通过如上的配置可以通过如下请求来测试 批量插入

POST /users/batch

Content-Type: application/json

[

{"name": "Alice", "age": 30, "email": "alice@example.com"},

{"name": "Bob", "age": 25, "email": "bob@example.com"},

{"name": "Charlie", "age": 28, "email": "charlie@example.com"}

]

批量更新

PUT /users/batch

Content-Type: application/json

[

{"id": 1, "name": "Alice Smith", "age": 31, "email": "alice.smith@example.com"},

{"id": 2, "name": "Bob Brown", "age": 26, "email": "bob.brown@example.com"}

]

批量删除

DELETE /users/batch

Content-Type: application/json

[1, 2, 3] // 要删除的用户 ID 列表

逻辑删除

MyBatis-Plus 支持逻辑删除功能,可以通过在实体类的字段上添加 @TableLogic 注解来指定逻辑删除的字段,并在全局配置中启用逻辑删除功能。BaseMapper 支持根据条件进行逻辑删除操作,例如,selectPage 方法可以通过指定查询条件来查询被逻辑删除的记录。示例如下: 创建 User 实体类,并在需要逻辑删除的字段上添加 @TableLogic 注解

@Data

@TableName("user")

public class User {

@TableId

private Long id;

private String name;

private Integer age;

private String email;

@TableLogic // 逻辑删除字段

private Integer deleted; // 1 表示已删除,0 表示未删除

}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper {

}

创建 UserService 类,使用 UserMapper 进行逻辑删除操作

@Service

public class UserService extends ServiceImpl {

// 逻辑删除

public void deleteUser(Long id) {

this.removeById(id); // 使用 removeById 方法进行逻辑删除

}

// 查询所有用户(包括已删除的用户)

public List getAllUsers() {

return this.list(); // 查询所有用户

}

}

在控制器中调用 UserService 进行逻辑删除和查询操作

@RestController

@RequestMapping("/users")

public class UserController {

@Autowired

private UserService userService;

// 逻辑删除

@DeleteMapping("/{id}")

public void deleteUser(@PathVariable Long id) {

userService.deleteUser(id);

}

// 查询所有用户(包括已删除的用户)

@GetMapping("/all")

public List getAllUsers() {

return userService.getAllUsers();

}

}

在 MyBatis-Plus 的配置类中启用逻辑删除功能(通常在 application.yml 或 application.properties 中配置)

mybatis-plus:

global-config:

db-config:

logic-delete-value: 1 # 逻辑删除的值

logic-not-delete-value: 0 # 未删除的值

通过上述的配置可实现逻辑删除与查询

DELETE /users/{id}

GET /users/all

乐观锁

MyBatis-Plus 支持乐观锁功能,可以通过在实体类的字段上添加 @Version 注解来指定乐观锁的字段,并在全局配置中启用乐观锁功能。BaseMapper 提供了根据乐观锁字段进行更新操作的方法,例如,updateById 方法可以通过乐观锁字段来实现乐观锁更新。示例如下: 创建 User 实体类,并在需要进行乐观锁的字段上添加 @Version 注解

@Data

@TableName("user")

public class User {

@TableId

private Long id;

private String name;

private Integer age;

private String email;

@Version // 乐观锁字段

private Integer version; // 版本号

}

创建 UserMapper 接口,继承 BaseMapper

public interface UserMapper extends BaseMapper {

}

创建 UserService 类,使用 UserMapper 进行乐观锁更新操作

@Service

public class UserService extends ServiceImpl {

// 更新用户信息(乐观锁)

public boolean updateUser(User user) {

return this.updateById(user); // 使用 updateById 方法进行乐观锁更新

}

}

在控制器中调用 UserService 进行更新操作

@RestController

@RequestMapping("/users")

public class UserController {

@Autowired

private UserService userService;

// 更新用户信息

@PutMapping

public boolean updateUser(@RequestBody User user) {

return userService.updateUser(user);

}

}

通过上述配置,可模拟请求如下:

PUT /users

Content-Type: application/json

{

"id": 1,

"name": "Alice Smith",

"age": 31,

"email": "alice.smith@example.com",

"version": 1 // 提交时需要提供当前的版本号

}

乐观锁的更新机制:在执行更新时,MyBatis-Plus 会自动检查 version 字段的值。如果数据库中的 version 值与传入的值不匹配,则更新操作会失败,返回 0(表示没有更新任何记录)。这可以有效防止并发更新导致的数据不一致问题。