[toc]
| 单词 | 词性 | 音标 | 含义 |
|---|---|---|---|
| Logic | n. | /ˈlɒdʒɪk/ | 逻辑(@TableLogic 逻辑删除:删除操作改为给字段打标记,不真正删数据) |
| Delete | v. | /dɪˈliːt/ | 删除(逻辑删除后,查询自动过滤已删除数据) |
| Fill | v. | /fɪl/ | 填充(@TableField(fill=...) 让框架自动为字段赋值,如创建时间) |
| Handler | n. | /ˈhændlə(r)/ | 处理器(MetaObjectHandler 负责在插入/更新时给字段赋值) |
Lecture09-逻辑删除与字段自动填充
一、逻辑删除
1、什么是逻辑删除
现实业务中,很多数据不能真的删掉:
- 订单删了,财务对账就没了依据
- 用户删了,历史关联数据会乱
- 删错了无法恢复
所以有了「逻辑删除」:不执行 DELETE,而是给记录打一个删除标记(比如 deleted=1 表示已删除)。查询时自动过滤掉标记为已删除的数据,看起来就像删了一样,但数据还在表里。
本质上是把 DELETE 语句改成 UPDATE 语句,执行逻辑删除时只是把指定字段从 0 改成 1
MyBatis-Plus 对逻辑删除做了全自动支持:加一个注解、配两行配置,删除、查询全部自动处理。
2、准备:给表加 deleted 字段
ALTER TABLE t_emp ADD COLUMN is_deleted TINYINT NOT NULL DEFAULT 0 COMMENT '逻辑删除标记:0未删除,1已删除';
3、实体类加注解
@Data
@TableName("t_emp")
public class Employee {
@TableId(type = IdType.AUTO)
private Integer empId;
// ...其他字段
@TableLogic // 逻辑删除字段
private Integer isDeleted;
}
4、效果演示
①删除变成了更新
@Test
public void testLogicDelete() {
int rows = employeeMapper.deleteById(4);
System.out.println("rows = " + rows);
}
控制台日志——不再是 DELETE,而是 UPDATE:
==> Preparing: UPDATE t_emp SET deleted=1 WHERE emp_id=? AND deleted=0
==> Parameters: 4(Integer)
②查询自动过滤
@Test
public void testSelectAfterDelete() {
List<Employee> employeeList = employeeMapper.selectList(null);
employeeList.forEach(System.out::println);
}
==> Preparing: SELECT emp_id,emp_no,emp_name,emp_salary,emp_birthday,phone_num,dept_id FROM t_emp WHERE is_deleted=0
emp_id=4 的员工(刚才逻辑删除的)不会出现在结果里。框架自动加了 AND is_deleted=0。
效果总结:逻辑删除后,
deleteById、selectList、updateById等所有方法都会自动带上is_deleted=0条件——完全不用我们操心。
5、补充:全局配置(推荐)
除了在实体类上加 @TableLogic,也可以在配置文件中统一声明逻辑删除字段,两种方式可以同时存在:
mybatis-plus.global-config.db-config.logic-delete-field=isDeleted
mybatis-plus.global-config.db-config.logic-delete-value=1
mybatis-plus.global-config.db-config.logic-not-delete-value=0
实际项目中通常「全局配置 + 实体注解」双保险。本教程演示用实体注解就够。
二、字段自动填充
1、问题
create_time(创建时间)、update_time(更新时间)这两个字段几乎每张表都有。如果每次都手动 set,代码啰嗦还容易忘。MyBatis-Plus 提供字段自动填充:插入时自动填创建时间,更新时自动填更新时间。
2、准备:给表加时间字段
ALTER TABLE t_emp
ADD COLUMN create_time DATETIME COMMENT '创建时间',
ADD COLUMN update_time DATETIME COMMENT '更新时间';
3、实体类字段声明填充策略
@Data
@TableName("t_emp")
public class Employee {
@TableId(type = IdType.AUTO)
private Integer empId;
// ...其他字段
@TableLogic
private Integer deleted;
@TableField(fill = FieldFill.INSERT) // 插入时自动填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入和更新时都自动填充
private LocalDateTime updateTime;
}
FieldFill 取值:
| 取值 | 触发时机 |
|---|---|
FieldFill.INSERT | 插入时填充 |
FieldFill.UPDATE | 更新时填充 |
FieldFill.INSERT_UPDATE | 插入和更新时都填充 |
FieldFill.DEFAULT | 不填充(默认) |
4、编写填充处理器
实现 MetaObjectHandler 接口,告诉框架「填充什么值」:
package com.atguigu.mp.config;
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) {
// 插入时:createTime 和 updateTime 都填当前时间
this.strictInsertFill(metaObject, "createTime", LocalDateTime.class, LocalDateTime.now());
this.strictInsertFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
@Override
public void updateFill(MetaObject metaObject) {
// 更新时:只填 updateTime
this.strictUpdateFill(metaObject, "updateTime", LocalDateTime.class, LocalDateTime.now());
}
}
注意:
strictInsertFill只在字段值为 null 时才填充,避免覆盖我们手动设置的值。
5、效果演示
@Test
public void testAutoFill() {
Employee employee = new Employee();
employee.setEmpNo("No.10006");
employee.setEmpName("周八");
employee.setEmpSalary(new BigDecimal("7000.00"));
employee.setEmpBirthday(new Date());
employee.setPhoneNum("13511110006");
employee.setDeptId(1);
// 插入:不手动设置 createTime / updateTime
employeeMapper.insert(employee);
// 插入后自动填充了
System.out.println("createTime = " + employee.getCreateTime());
System.out.println("updateTime = " + employee.getUpdateTime());
}
控制台日志:
==> Preparing: INSERT INTO t_emp ( emp_no, emp_name, emp_salary, emp_birthday, phone_num, dept_id, create_time, update_time, deleted ) VALUES ( ?, ?, ?, ?, ?, ?, ?, ?, ? )
==> Parameters: No.10006(String), ..., 2026-09-19T10:30:00(LocalDateTime), 2026-09-19T10:30:00(LocalDateTime), 0(Integer)
再调用一次 updateById,观察 update_time 自动更新、create_time 保持不变。
三、本章小结
- 逻辑删除:
@TableLogic+ 配置,删除变更新、查询自动过滤,数据不真删 - 自动填充:
@TableField(fill = ...)声明策略 + 实现MetaObjectHandler提供值 - 常用组合:
deleted(逻辑删除)+create_time/update_time(自动填充),几乎是每张表的标配 - 两个功能都是"配一次,全表生效",这正是 MyBatis-Plus 提升效率的典型场景
下一章学习乐观锁,解决并发更新数据丢失的问题。