SpringBoot 整合 MyBatis-Plus 实现逻辑删除与自动填充实战

举报
JiHua 发表于 2026/10/22 07:54:59 2026/10/22
【摘要】 在业务开发中,很多场景不会直接物理删除数据库数据,而是采用逻辑删除标记数据,同时创建时间、更新时间、操作人这类字段重复赋值十分繁琐。本文结合 MyBatis-Plus 实战,配置逻辑删除与字段自动填充,附带完整代码,讲解底层原理和常见踩坑点,适合后端开发快速落地。

前言

日常业务系统里,订单、用户、文章等数据,一般不使用 DELETE 语句直接删除。物理删除之后数据很难恢复,不利于数据追溯、统计排查。行业主流方案是逻辑删除:增加一个标记字段,删除时更新标记,查询时自动过滤已删除数据。

除此之外,每张表几乎都会有 create_time、update_time、create_by、update_by,每次新增、修改都手动赋值,大量重复样板代码。MyBatis-Plus 提供了自动填充功能,配合逻辑删除配置,一行配置即可生效,极大简化开发。

一、Maven 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>com.baomidou</groupId>
    <artifactId>mybatis-plus-boot-starter</artifactId>
    <version>3.5.3.1</version>
</dependency>
<dependency>
    <groupId>com.mysql</groupId>
    <artifactId>mysql-connector-j</artifactId>
    <scope>runtime</scope>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <optional>true</optional>
</dependency>

二、数据库表设计

示例用户表 t_user

CREATE TABLE `t_user` (
  `id` BIGINT PRIMARY KEY AUTO_INCREMENT COMMENT '主键ID',
  `username` VARCHAR(50) NOT NULL COMMENT '用户名',
  `nickname` VARCHAR(50) COMMENT '昵称',
  `create_time` DATETIME COMMENT '创建时间',
  `update_time` DATETIME COMMENT '更新时间',
  `deleted` TINYINT DEFAULT 0 COMMENT '逻辑删除 0未删除 1已删除'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

约定:0 = 正常,1 = 已删除。

三、YAML 配置

spring:
  datasource:
    driver-class-name: com.mysql.cj.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test_db?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    username: root
    password: 123456

mybatis-plus:
  global-config:
    db-config:
      # 逻辑删除值
      logic-delete-value: 1
      # 逻辑未删除值
      logic-not-delete-value: 0
  configuration:
    map-underscore-to-camel-case: true
    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl

四、实体类编写

import com.baomidou.mybatisplus.annotation.*;
import lombok.Data;
import java.time.LocalDateTime;

@Data
@TableName("t_user")
public class User {
    @TableId(type = IdType.AUTO)
    private Long id;

    private String username;
    private String nickname;

    @TableField(fill = FieldFill.INSERT)
    private LocalDateTime createTime;

    @TableField(fill = FieldFill.INSERT_UPDATE)
    private LocalDateTime updateTime;

    @TableLogic
    private Integer deleted;
}

FieldFill.INSERT:新增时自动填充;
FieldFill.INSERT_UPDATE:新增和修改都自动填充。

五、MetaObjectHandler 自动填充处理器

这是自动填充的核心,交给 Spring 管理:

import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler;
import org.apache.ibatis.reflection.MetaObject;
import org.springframework.stereotype.Component;
import java.time.LocalDateTime;

@Component
public class MyMetaObjectHandler implements MetaObjectHandler {

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

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

如果需要填充操作人,从上下文获取当前登录用户ID,在这里扩展即可。

六、Mapper、Service 层

Mapper

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import org.apache.ibatis.annotations.Mapper;

@Mapper
public interface UserMapper extends BaseMapper<User> {
}

Service

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> {
}

七、测试 Controller

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/user")
@RequiredArgsConstructor
public class UserController {

    private final UserServiceImpl userService;

    @GetMapping("/add")
    public String add() {
        User user = new User();
        user.setUsername("zhangsan");
        user.setNickname("张三");
        userService.save(user);
        return "新增成功";
    }

    @GetMapping("/del")
    public String del(Long id) {
        // 逻辑删除,底层执行 UPDATE t_user SET deleted=1,update_time=? WHERE id=? AND deleted=0
        userService.removeById(id);
        return "逻辑删除成功";
    }

    @GetMapping("/page")
    public Page<User> page() {
        // 自动拼接 WHERE deleted=0,查询不到已删除数据
        return userService.page(new Page<>(1,10));
    }
}

八、重点:如何查询被逻辑删除的数据

业务上有时候需要后台恢复、查看已删除记录,MP 默认自动过滤,想要查全部,需要写自定义 SQL:

@Select("SELECT * FROM t_user WHERE id = #{id}")
User selectRawById(Long id);

注意:不要直接关闭全局逻辑删除配置,会影响全部查询。

九、常见坑汇总

  1. 自动填充不生效
  • 忘记加 @Component 把 MetaObjectHandler 交给Spring;
  • 实体字段名和填充字符串不一致(大小写、驼峰下划线);
  • 手动给字段赋值,手动值优先级高于自动填充。
  1. 逻辑删除是 UPDATE,不是 DELETE
    开启逻辑删除之后,removeById 不再执行 delete,变成 update。
  2. 版本低于 3.3.0 配置方式不一样
    新版本推荐全局配置 + @TableLogic。
  3. 联表查询时,MP 不会自动带上 deleted 条件
    多表 join 的自定义 SQL,需要自己手动加上 AND deleted = 0。

十、总结

逻辑删除 + 自动填充是后台项目的标配能力。MyBatis-Plus 封装后配置简单,减少大量重复代码。开发时要分清:自带方法自动过滤删除标记,手写自定义SQL必须自己处理删除条件;同时注意自动填充的执行时机,避免和手动赋值冲突。逻辑删除的数据需要规划定期归档清理,防止单表数据无限膨胀影响查询性能。


【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。