SpringBoot4集成MyBatis-Plus实现单表操作零SQL的实践教学
作者:gis开发之家
国内互联网项目最主流的持久层方案不是 JPA,而是 MyBatis‑Plus——既保留 SQL 可控性,又提供单表零 SQL 的极致效率。本文将手把手带你整合 MP、玩转条件构造器、代码生成器、分页插件与逻辑删除,直接对标企业级开发。
一、MyBatis‑Plus 是什么?和 JPA / MyBatis 比啥区别?
定位一句话
MyBatis‑Plus = MyBatis + 通用 Mapper + 条件构造器 + 代码生成 + 分页/逻辑删除开箱即用
不替换 MyBatis,只是在上面加了一层"增强",所以原生 XML 照样能用。
三者对比
| 方案 | SQL 可控性 | 单表 CRUD 成本 | 复杂 SQL | 国内流行度 |
|---|---|---|---|---|
| MyBatis 原生 | ⭐⭐⭐⭐⭐ | 手写 XML,成本高 | ⭐⭐⭐⭐⭐ | 高 |
| Spring Data JPA | ⭐⭐(自动生成) | 几乎零代码 | ⭐⭐(复杂 JPQL 难写) | 中 |
| MyBatis‑Plus | ⭐⭐⭐⭐⭐ | 零 SQL(BaseMapper) | ⭐⭐⭐⭐⭐(XML 随时补) | 最高 |
选型建议:
- 快速后台管理 / 单表为主 → MyBatis‑Plus
- 强领域模型 / DDD → JPA
- 超复杂报表 / 多表关联 → MyBatis‑Plus + 手写 XML
二、Spring Boot 4 整合 MyBatis‑Plus
引入依赖
<dependencies>
<!-- Web -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- MyBatis-Plus(适配 Spring Boot 4 / Spring 6) -->
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-spring-boot3-starter</artifactId>
<version>3.5.7</version>
</dependency>
<!-- MySQL 驱动 -->
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<scope>runtime</scope>
</dependency>
<!-- Druid 连接池 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid-spring-boot-3-starter</artifactId>
<version>1.2.23</version>
</dependency>
<!-- Lombok(可选,简化实体) -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>注意:Spring Boot 4 必须选 mybatis-plus-spring-boot3-starter,不要用老版 mybatis-plus-boot-starter。
基础配置(application.yml)
spring:
datasource:
type: com.alibaba.druid.pool.DruidDataSource
url: jdbc:mysql://localhost:3306/mp_demo?useUnicode=true&characterEncoding=utf-8&serverTimezone=Asia/Shanghai&useSSL=false
username: root
password: root
mybatis-plus:
configuration:
map-underscore-to-camel-case: true # 下划线转驼峰
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl # 打印 SQL(开发用)
global-config:
db-config:
id-type: auto # 主键自增
logic-delete-field: deleted # 逻辑删除字段名
logic-delete-value: 1
logic-not-delete-value: 0
mapper-locations: classpath*:mapper/*.xml # 如需手写 XML启动类加扫描
@SpringBootApplication
@MapperScan("com.example.demo.mapper")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}三、实体与 Mapper(零 SQL 核心)
实体类(@TableName / @TableId / @TableField)
@Data
@TableName("t_user")
public class User {
@TableId(type = IdType.AUTO)
private Long id;
@TableField("username")
private String username;
private String email;
private Integer age;
@TableField(fill = FieldFill.INSERT)
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE)
private LocalDateTime updateTime;
@TableLogic // 逻辑删除
private Integer deleted;
}核心注解速查:
| 注解 | 作用 |
|---|---|
@TableName | 表名映射 |
@TableId | 主键(IdType.AUTO / ASSIGN_ID / UUID) |
@TableField | 字段映射 / 自动填充 |
@TableLogic | 逻辑删除标记 |
@Version | 乐观锁字段 |
Mapper 接口(就这么一行)
public interface UserMapper extends BaseMapper<User> {
}BaseMapper 已内置 17 个方法:
insert / insertBatchSomeColumn deleteById / deleteByMap / delete / deleteBatchIds updateById / update selectById / selectBatchIds / selectByMap / selectOne / selectList / selectCount selectPage / selectMaps / selectObjs
不用写任何 XML,单表全搞定。
直接开用
@Service
public class UserService {
@Autowired
private UserMapper userMapper;
public User create(User user) {
userMapper.insert(user);
return user;
}
public User getById(Long id) {
return userMapper.selectById(id);
}
public List<User> listAll() {
return userMapper.selectList(null);
}
public void delete(Long id) {
userMapper.deleteById(id); // 逻辑删除(配置了 @TableLogic)
}
}四、条件构造器(QueryWrapper / LambdaQueryWrapper)
QueryWrapper(字段名字符串)
QueryWrapper<User> wrapper = new QueryWrapper<>();
wrapper.gt("age", 18)
.like("username", "zhang")
.orderByDesc("create_time");
List<User> list = userMapper.selectList(wrapper);LambdaQueryWrapper(推荐,防字段名写错)
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.gt(User::getAge, 18)
.like(User::getUsername, "zhang")
.between(User::getCreateTime, start, end)
.orderByDesc(User::getCreateTime);
List<User> list = userMapper.selectList(wrapper);编译期校验字段名,重构安全,强烈推荐
常用条件方法速查
| 方法 | SQL 片段 |
|---|---|
.eq(col, val) | = |
.ne(col, val) | != |
.gt / ge / lt / le | > >= < <= |
.like / notLike | LIKE %x% |
.likeLeft / likeRight | %x / x% |
.in(col, list) | IN (...) |
.between(col, a, b) | BETWEEN a AND b |
.isNull / isNotNull | IS NULL / IS NOT NULL |
.orderByAsc / Desc | ORDER BY |
.last("LIMIT 1") | 拼接原生片段(慎用) |
UpdateWrapper 更新
LambdaUpdateWrapper<User> update = new LambdaUpdateWrapper<>();
update.eq(User::getId, 1L)
.set(User::getAge, 20)
.set(User::getEmail, "new@test.com");
userMapper.update(null, update);五、分页插件(必须配置,否则分页失效)
配置类
@Configuration
public class MybatisPlusConfig {
@Bean
public MybatisPlusInterceptor mybatisPlusInterceptor() {
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
// 分页插件(指定数据库类型)
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
// 乐观锁插件
interceptor.addInnerInterceptor(new OptimisticLockerInnerInterceptor());
// 防止全表更新
interceptor.addInnerInterceptor(new BlockAttackInnerInterceptor());
return interceptor;
}
}使用分页
public Page<User> pageUsers(int current, int size, Integer minAge) {
Page<User> page = new Page<>(current, size);
LambdaQueryWrapper<User> wrapper = new LambdaQueryWrapper<>();
wrapper.ge(minAge != null, User::getAge, minAge)
.orderByDesc(User::getCreateTime);
return userMapper.selectPage(page, wrapper);
}返回结构:
{
"records": [...],
"total": 128,
"size": 10,
"current": 1,
"pages": 13
}六、自动填充(createTime / updateTime)
实现 MetaObjectHandler
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {
@Override
public void insertFill(MetaObject metaObject) {
strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}配合实体上 @TableField(fill = ...) 自动生效
七、代码生成器(企业级提效神器)
引入依赖
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-generator</artifactId>
<version>3.5.7</version>
</dependency>
<dependency>
<groupId>org.freemarker</groupId>
<artifactId>freemarker</artifactId>
<version>2.3.33</version>
</dependency>生成脚本(一次性运行)
public class CodeGenerator {
public static void main(String[] args) {
FastAutoGenerator.create(
"jdbc:mysql://localhost:3306/mp_demo?useSSL=false&serverTimezone=Asia/Shanghai",
"root", "root")
.globalConfig(builder -> builder
.author("yourname")
.outputDir(System.getProperty("user.dir") + "/src/main/java")
.commentDate("yyyy-MM-dd")
.enableSwagger())
.packageConfig(builder -> builder
.parent("com.example.demo")
.entity("domain")
.mapper("mapper")
.service("service")
.controller("controller")
.mapperXml("mapper"))
.strategyConfig(builder -> builder
.entityBuilder()
.enableLombok()
.logicDeleteColumnName("deleted")
.versionColumnName("version")
.controllerBuilder()
.enableRestStyle()
.mapperBuilder()
.enableMapperAnnotation()
.enableBaseResultMap())
.templateEngine(new FreemarkerTemplateEngine())
.execute();
}
}一键生成 Entity + Mapper + Service + Controller + XML
八、逻辑删除 & 乐观锁(生产必配)
逻辑删除
实体字段:
@TableLogic private Integer deleted;
调用 deleteById() 实际执行:
UPDATE t_user SET deleted = 1 WHERE id = ? AND deleted = 0
查询自动追加:
SELECT * FROM t_user WHERE deleted = 0
乐观锁(@Version)
实体:
@Version private Integer version;
更新时自动:
UPDATE t_user SET ..., version = version + 1 WHERE id = ? AND version = ?
并发冲突抛 OptimisticLockException,可捕获重试。
九、Spring Boot 4 新变化 & 兼容性
- 必须使用 mybatis-plus-spring-boot3-starter(Spring 6 / Boot 4 基线)
- Hibernate / JPA 与 MP 可共存(不推荐混用,选一个)
- 虚拟线程下连接释放更及时
十、常见坑位总结
坑1:分页不生效,全表查询
没加 MybatisPlusInterceptor + PaginationInnerInterceptor
坑2:字段名不匹配(驼峰 vs 下划线)
开启 map-underscore-to-camel-case: true,或显式 @TableField
坑3:逻辑删除不生效
检查 @TableLogic + 全局 logic-delete-field 冲突(二选一即可)
坑4:ResultMap 报 Unknown Column
用代码生成器统一字段,避免手敲 XML 错位
坑5:MP 和 JPA Starter 同时引入冲突
二选一,不要都加
十一、本篇总结
- Spring Boot 4 用
mybatis-plus-spring-boot3-starter BaseMapper<T>提供单表零 SQL 的 17 个方法- 条件构造器用
LambdaQueryWrapper,类型安全 - 分页 / 乐观锁 / 防全表更新都靠
MybatisPlusInterceptor - 代码生成器一次性产出整套 CRUD,效率拉满
到此这篇关于SpringBoot4集成MyBatis-Plus实现单表操作零SQL的实践教学的文章就介绍到这了,更多相关SpringBoot集成MyBatis-Plus内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!
您可能感兴趣的文章:
- SpringBoot+MyBatis-Plus动态数据权限控制生产级落地方案详解
- SpringBoot整合MyBatis-Plus代码生成器的示例代码
- springboot4.x之knife4j文档与日志和mybatis-plus搭建完整指南
- SpringBoot+MyBatis-Plus实现配置多数据源并动态切换
- SpringBoot集成MyBatis-Plus的完整教程
- springboot之集成mybatis-plus、druid整合多数据源实践
- SpringBoot 集成 MyBatis/MyBatis-Plus 超详细教程
- springBoot使用mybatis-plus插件实现分页过程
- SpringBoot3.x与MyBatis-Plus兼容问题小结
- mybatis-plus集成springboot实现XML映射器方式
