MyBatis-Plus 数据访问¶
操作数据库。本书用 MyBatis-Plus(简称 MP)——SQL 透明可控、CRUD 自动生成、对前端人最直观。
Mapper 继承 BaseMapper,白嫖 CRUD¶
只要让你的 Mapper 继承 BaseMapper<实体>,一行 SQL 不写,自动获得一堆方法:
package com.javaglm.task.mapper;
import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.javaglm.task.entity.Task;
/**
* 任务 Mapper(第 26 章)。
* 继承 BaseMapper<Task>,白嫖一堆 CRUD 方法(insert/updateById/deleteById/selectById/selectList...),
* 一行 SQL 都不用写。需要自定义 SQL 时再在这里加方法 + 写 XML/注解。
*/
public interface TaskMapper extends BaseMapper<Task> {
}
自动获得的方法:
| 方法 | 作用 |
|---|---|
insert(task) |
插入 |
updateById(task) |
按 id 更新 |
deleteById(id) |
按 id 删除 |
selectById(id) |
按 id 查询 |
selectList(wrapper) |
条件查询 |
selectCount(wrapper) |
计数 |
selectPage(page, wrapper) |
分页查询 |
条件构造器:LambdaQueryWrapper¶
查询不用拼 SQL 字符串,用类型安全的 LambdaQueryWrapper:
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Task::getUserId, userId); // WHERE user_id = ?
if (status != null) {
wrapper.eq(Task::getStatus, status); // AND status = ?
}
wrapper.orderByDesc(Task::getCreateTime); // ORDER BY create_time DESC
List<Task> list = taskMapper.selectList(wrapper);
Task::getUserId 是方法引用(第 15 章),MP 据此推出列名 user_id(驼峰转下划线)。
分页:要注册插件¶
分页不是开箱即用,得注册分页插件,否则 page() 会查出全部:
package com.javaglm.task.config;
import com.baomidou.mybatisplus.annotation.DbType;
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;
/**
* MyBatis-Plus 配置(第 26 章):注册分页插件。
* 不加这个,page() 不会真的分页(会查出全部)。
*/
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
return interceptor;
}
}
实战:分页查询任务¶
Service 层组合 wrapper + page:
package com.javaglm.task.service.impl;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.javaglm.task.common.BizException;
import com.javaglm.task.dto.TaskRequest;
import com.javaglm.task.entity.Task;
import com.javaglm.task.mapper.TaskMapper;
import com.javaglm.task.service.TaskService;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
/**
* 任务服务实现(第 28 章)。
* 继承 ServiceImpl<TaskMapper, Task>:自动拥有 CRUD,Mapper 也自动注入。
* 业务逻辑写在这里(校验归属、组装数据),Controller 保持"瘦"。
*/
@Service
public class TaskServiceImpl extends ServiceImpl<TaskMapper, Task> implements TaskService {
@Override
public IPage<Task> pageTasks(long current, long size, Long userId, Integer status) {
LambdaQueryWrapper<Task> wrapper = new LambdaQueryWrapper<>();
wrapper.eq(Task::getUserId, userId);
if (status != null) {
wrapper.eq(Task::getStatus, status);
}
wrapper.orderByDesc(Task::getCreateTime);
return this.page(new Page<>(current, size), wrapper);
}
@Override
public Task createTask(TaskRequest req, Long userId) {
Task task = new Task();
task.setTitle(req.getTitle());
task.setDescription(req.getDescription());
task.setStatus(req.getStatus() == null ? 0 : req.getStatus());
task.setUserId(userId);
task.setCreateTime(LocalDateTime.now());
task.setUpdateTime(LocalDateTime.now());
this.save(task);
return task;
}
@Override
public Task updateTask(Long id, TaskRequest req, Long userId) {
Task task = this.getById(id);
if (task == null || !task.getUserId().equals(userId)) {
throw new BizException(404, "任务不存在或无权操作");
}
task.setTitle(req.getTitle());
task.setDescription(req.getDescription());
if (req.getStatus() != null) {
task.setStatus(req.getStatus());
}
task.setUpdateTime(LocalDateTime.now());
this.updateById(task);
return task;
}
@Override
public void deleteTask(Long id, Long userId) {
Task task = this.getById(id);
if (task == null || !task.getUserId().equals(userId)) {
throw new BizException(404, "任务不存在或无权操作");
}
this.removeById(id); // @TableLogic:实际执行逻辑删除
}
}
看 pageTasks 方法:组装条件 → this.page(new Page<>(current, size), wrapper) 返回 IPage<Task>,里面含 records(当前页数据)、total(总数)、current/size(页码/页大小)。
为什么不用 JPA¶
- MyBatis-Plus:你看得见 SQL(或自动生成可控),调试简单,国内主流。
- JPA:声明接口自动生成 SQL,优雅但"魔法"重,复杂查询难写,国内用得少。
对前端人:MP 的"写条件→出数据"和你的"发请求→拿数据"心智最接近。
需要自定义 SQL 怎么办
BaseMapper 不够用时,在 Mapper 接口加方法 + 写 XML 或注解 SQL。本书任务系统的需求 BaseMapper 全够了,不展开。
:octicons-arrow-left-16: 上一章:配置管理 | 下一章:数据库设计实战