【一文搞懂】MyBatis-Plus中核心类BaseMapper的基础和进阶用法
文章目录
基础用法进阶用法自定义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
// 插入一条记录
int insert(T entity);
// 根据主键删除记录
int deleteById(Serializable id);
// 根据columnMap条件,删除记录
int deleteByMap(@Param("cm") Map
// 根据条件构造器删除记录
int delete(@Param("ew") Wrapper
// 根据ID列表批量删除
int deleteBatchIds(@Param("coll") Collection extends Serializable> idList);
// 根据ID更新记录(全部字段)
int updateById(@Param("et") T entity);
// 根据条件构造器更新记录
int update(@Param("et") T entity, @Param("ew") Wrapper
// 根据ID查询记录
T selectById(Serializable id);
// 根据ID列表批量查询
List
// 根据columnMap条件查询记录
List
// 根据条件构造器查询一条记录
T selectOne(@Param("ew") Wrapper
// 根据条件构造器查询记录数
Integer selectCount(@Param("ew") Wrapper
// 根据条件构造器查询记录列表
List
// 根据条件构造器查询全部记录,将每条记录封装为一个Map对象,List
List
// 根据条件构造器查询全部记录,将每条记录封装为一个Object数组,List
List
// 分页查询,返回实体类的分页结果
// 分页查询,返回的Map
}
简单应用示例: 假设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
}
方式二:使用XML文件自定义SQL方法
在 Mapper 接口中声明方法
public interface CourseBaseMapper extends BaseMapper
List
}
在 resources/mapper/ 目录下创建一个名为 CourseBaseMapper.xml 的文件。这个文件与 CourseBaseMapper 接口绑定。
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
SELECT * FROM course_base WHERE status = #{status}
针对上述两种方式,在业务逻辑中则可调用这些自定义的方法
@Service
public class CourseService {
@Autowired
private CourseBaseMapper courseBaseMapper;
public List
return courseBaseMapper.selectCoursesByName(nameKeyword); // 使用注解方式的方法
}
public List
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
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.eq("status", "未发布") // 条件:状态为 "未发布"
.set("status", "已发布"); // 更新状态为 "已发布"
return courseBaseMapper.update(null, updateWrapper); // 执行更新操作
}
}
使用 LambdaQueryWrapper 进行查询
LambdaQueryWrapper 是 QueryWrapper 的 lambda 表达式版本,它在属性引用上更安全(不会因为字段名拼写错误而出错),适合复杂查询。
示例:查询所有创建人是 “张三” 且课程等级为 “高级” 的记录
@Service
public class CourseService {
@Autowired
private CourseBaseMapper courseBaseMapper;
public List
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.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
Page
return this.baseMapper.selectPage(page, null); // 查询并返回分页结果
}
}
在控制器中调用 UserService 进行分页查询
@RestController
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/users")
public Page
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
this.saveBatch(userList); // 使用 saveBatch 方法进行批量插入
}
// 批量更新
public void updateBatch(List
this.updateBatchById(userList); // 使用 updateBatchById 方法进行批量更新
}
// 批量删除
public void deleteBatch(List
this.removeByIds(ids); // 使用 removeByIds 方法进行批量删除
}
}
在控制器中调用 UserService 进行批量操作
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
// 批量插入
@PostMapping("/batch")
public void insertBatch(@RequestBody List
userService.insertBatch(userList);
}
// 批量更新
@PutMapping("/batch")
public void updateBatch(@RequestBody List
userService.updateBatch(userList);
}
// 批量删除
@DeleteMapping("/batch")
public void deleteBatch(@RequestBody List
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
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
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(表示没有更新任何记录)。这可以有效防止并发更新导致的数据不一致问题。