MyBatis-Plus 分页插件与字段自动填充:两行配置告别 CRUD 重复劳动

大家好,我是晚安code。

写过几轮 CRUD 的朋友,下面这两件事你大概率天天干:分页查询要手写 countlimit,换张表就改一遍;每次 insert 前还得手动 setCreateTime(),漏一次线上就埋个坑。这两件破事,MyBatis-Plus 两个内置能力就能全包圆------分页插件和字段自动填充,两行配置,一次配好。今天用「用户管理」当例子,把思路和代码都给你捋清楚,收藏这篇,下次直接抄。

一、写 CRUD 时最烦的两件事

先说说痛点,你肯定有共鸣。

第一件,分页查询。 早期写分页,每张表都得 copy 一份带 countlimit 的 SQL,还得手动算 offset。表一多,光维护这些分页语句就够呛,改个页码逻辑还得小心别把 SQL 拼错。

第二件,审计字段。 也就是 create_timeupdate_time 这种"谁在什么时候干的"的字段。每次新增、每次修改,都要在 Service 里手动 set 一遍当前时间。手一抖忘了,数据库里就留下一条没有时间戳的记录,排查时一脸懵。

二、MyBatis-Plus 到底是什么

MyBatis-Plus(MP):MyBatis 的增强工具,只做增强不做改变,不会影响你已有的 MyBatis 代码。你可以理解为「MyBatis 的自动挡」------不用换发动机,挂个挡就能自动换挡。

它最拿手的,就是把单表 CRUD 里那些写烦了的模板代码收编成内置能力。分页、条件查询、逻辑删除、字段填充,这些在原生 MyBatis 里要手写的地方,MP 都替你包好了。

三、分页插件:一页一页查,不用再拼 SQL

分页插件解决的不是"能不能分页",而是"别让我每张表都重写一遍 count + limit"。配一次,全项目生效。

分页插件(PaginationInnerInterceptor):MyBatis-Plus 内置的分页拦截器,会自动拦截分页 SQL,帮你拼好 count 统计和 limit 截断。就像点外卖时的"自动凑满减"------你不用自己算,平台帮你凑好。

1)加依赖

xml 复制代码
<!-- MyBatis-Plus 3.5.x,2026 年 8 月实测 -->
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.7</version>
</dependency>

2)注册插件

java 复制代码
// MyBatis-Plus 3.5.x,2026 年 8 月实测
@Configuration
public class MybatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
        // 注册分页插件,指定数据库方言
        interceptor.addInnerInterceptor(
            new PaginationInnerInterceptor(DbType.MYSQL));
        return interceptor;
    }
}

DbType.MYSQL 就是告诉插件"我连的是 MySQL",方言不同,分页拼接语法就不同。

3)使用

java 复制代码
// 查第 2 页,每页 10 条
Page<User> page = new Page<>(2, 10);

// 一条 SQL 都不用写,插件自动拼 count + limit
IPage<User> result = userMapper.selectPage(page, null);

// 当前页的数据
List<User> users = result.getRecords();
// 总条数,前端分页条靠它渲染
long total = result.getTotal();

核心就一个 Page 对象 + 一个 selectPage 方法。至于 count 怎么统计、offset 怎么算、limit 拼在哪儿,都是插件在底层替你干。

看一眼分页插件的执行链路,就明白为什么你不用写 SQL 了

四、踩坑:分页插件失效

可能有人会问:分页插件配了怎么还是不生效?

九成是这俩原因:要么 PaginationInnerInterceptor 没注册进 MybatisPlusInterceptor(记得加进 addInnerInterceptor),要么 mybatis-plus 版本太旧,老版本分页插件类和现在不一样。先把版本升到 3.5.x 再试。

另外有个细节我踩过:分页插件要声明在拦截器链里 。有些教程让直接 new PaginationInnerInterceptor() 就完事,其实它得挂在 MybatisPlusInterceptor 里面才算数,顺序放前面更稳妥。否则你 selectPage 是能调用,但 SQL 不拼 limit,全表查出来再分页------慢不说,还白折腾。

五、字段自动填充:创建/更新时间不用再手动

审计字段自动填充,本质是把"每次都要记得"改成"配一次永远生效"。你只管业务字段,时间戳交给框架。

MetaObjectHandler(元对象处理器):MyBatis-Plus 的字段填充接口,执行 insert 或 update 时会自动回调。你可以理解为「数据库操作的自动盖章机」------插入或更新时,自动给你盖上当前时间。

审计字段 :数据库表里 create_timeupdate_time 这类记录"谁、在什么时候、对数据干了什么"的字段。名字听着像审计报告,其实就是让你知道每条数据啥时候来的、啥时候改的。

1)实体加注解

java 复制代码
@Data
@TableName("user")
public class User {

    @TableId(type = IdType.ASSIGN_ID)
    private Long id;

    private String username;

    // 插入时自动填充
    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    // 插入和更新时都自动填充
    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;
}

@TableField(fill = ...) 是开关,FieldFill.INSERT 表示只插入时填,FieldFill.INSERT_UPDATE 表示插入和更新都填。写明白后,Create、Update 两个操作想让它什么时候盖时间戳,你说了算。

2)实现处理器

java 复制代码
// 注册成 Spring Bean,MyBatis-Plus 自动识别
@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

    @Override
    public void insertFill(MetaObject metaObject) {
        this.strictInsertFill(metaObject, "createTime",
                LocalDateTime.class, LocalDateTime.now());
        this.strictInsertFill(metaObject, "updateTime",
                LocalDateTime.class, LocalDateTime.now());
    }

    @Override
    public void updateFill(MetaObject metaObject) {
        this.strictUpdateFill(metaObject, "updateTime",
                LocalDateTime.class, LocalDateTime.now());
    }
}

insertFill 管插入,updateFill 管更新。注意字段名要和实体里一致,"createTime" 对应 createTime,别写成 create_time,不然按字段名填不上。

六、踩坑:自动填充不生效

可能有人会问:自动填充没效果,字段还是空的?

三个原因对号入座:① @TableField(fill = ...) 没写;② MetaObjectHandler 忘了加 @Component,没注册成 Spring Bean;③ strictInsertFill 里字段名写错,比如把 "createTime" 写成 "create_time"

这个坑我实打实踩过。一开始漏了 @Componentinsert 完了 create_time 还是 null,查了半天没头绪。

另外说一句,strictInsertFill 只在字段值还是 null 时才填。你要是手动 set 了值,它就尊重你的值,不会覆盖。这个特性挺实用------想特殊处理的字段,你可以自己控制。

七、手动 vs MyBatis-Plus:一张表看清差距

手动写分页和手动填时间戳,是 CRUD 里最不值得花时间的两件事。能交给框架的,别自己扛。

场景 手动做法 MyBatis-Plus 做法 你要配的
分页查询 每张表手写 count + limit,换表改一遍 selectPage + Page,插件自动拼 SQL 注册一个分页插件 Bean
创建时间 insert 前手动 setCreateTime() @TableField(fill = INSERT) 自动填 实现 MetaObjectHandler
更新时间 update 前手动 setUpdateTime() INSERT_UPDATE 插入更新都覆盖 同一个 handler 搞定

八、总结与延伸

这两样配好之后,我写 CRUD 基本就剩业务逻辑本身了:分页用 Page,时间戳交给 MetaObjectHandler,实体上两个注解,配置类里几行代码。短项目半天能搭完的增删改查,至少省掉一大半模板活。

我的看法很直接:只要你的项目用了 MyBatis-Plus,分页插件和字段自动填充就该是标配,配一次长期省心。 还没用 MP 的项目,光为了这俩能力迁移也值。

想再深入,可以翻 MyBatis-Plus 官方文档看逻辑删除、乐观锁、条件构造器(搜:MyBatis-Plus 官网 核心功能)。工具版本以 3.5.x 为准,本文随版本更新同步修订,最后更新:2026 年 8 月。

我是晚安code,持续分享编程干货。觉得有用的话记得点赞收藏和关注~也欢迎在评论区聊聊:你在用 MyBatis-Plus 时还靠它解决过哪些 CRUD 痛点?

相关推荐
SQL-First布道者21 小时前
持久层框架的评价标准:只有一个
java·spring boot·spring·tomcat·mybatis·spring jdbc
步行cgn1 天前
MyBatis 高级映射与延迟加载完全指南
java·tomcat·mybatis
mashirro1 天前
记一次基于ruoyi-vue新增小程序服务模块,小程序登陆相关
vue.js·小程序·mybatis
边境悍匪1 天前
蜗牛学苑 Java 智能体学习 Day24|SpringBoot 整合 MyBatis、分层解耦思维导图复盘
java·数据库·spring boot·学习·mybatis
抓哇小菜鸡2 天前
Spring Boot + 本地大模型(Ollama/DeepSeek) + MyBatis-Plus 企业级智能体数据分析系统从零到一源码全解析
spring boot·后端·mybatis
步行cgn2 天前
MyBatis 批量插入时 Parameter ‘carNum‘ not found 错误详解
mybatis
何以解忧,唯有..2 天前
深入理解与应对:Redis 缓存雪崩、击穿、穿透三大经典问题
redis·缓存·mybatis
andongni2033 天前
后端参数校验
spring boot·后端·mybatis
Devin~Y4 天前
从内容社区到AI智能客服:Spring Boot + Spring Cloud + Spring AI 全栈实战面试拆解
java·spring boot·redis·elasticsearch·spring cloud·kafka·mybatis