逻辑删除与公共字段填充思路

生产系统很少物理删数据:删了无法审计、难以恢复。业界普遍用"逻辑删除"——加一个标记列,删除只是 UPDATE。同时 create_time、update_time 这类公共字段每张表都有,重复手写很烦。本节讲纯 MyBatis 与 MyBatis-Plus 两种思路。

逻辑删除:纯 MyBatis 怎么做

逻辑删除 = 表加 deleted 标记(0 有效 / 1 删除),删除写成 UPDATE,所有查询都带 deleted = 0。纯 MyBatis 没有内建开关,靠约定与片段复用:

<!-- 删除即更新(也可用 @Update 注解) -->
<!-- UPDATE user SET deleted = 1 WHERE id = #{id} -->
<sql id="notDeleted">
    AND deleted = 0
</sql>
<select id="selectById" resultType="User">
    SELECT id, name, deleted FROM user
    WHERE id = #{id} <include refid="notDeleted"/>
</select>

风险是"每条 SQL 都得记得带条件",容易漏;想全局兜底要写拦截器自动拼条件,工程量大,此时考虑 MyBatis-Plus 更划算。

MyBatis-Plus:@TableLogic

MP 把逻辑删除做成了标准能力:实体字段加注解,删除与查询自动改写:

@TableLogic                    // 逻辑删除标记字段
private Integer deleted;

此后 deleteById(id) 实际执行 UPDATE user SET deleted=1 WHERE id=?selectByIdselectList 自动追加 deleted=0,无需手写。字段名全局统一时,可用 logic-delete-field: deleted 免注解,值可通过 logic-delete-value / logic-not-delete-value 定制(以官方文档为准)。

公共字段填充思路

create_time / update_time 也分两派:

  • 数据库默认值DEFAULT CURRENT_TIMESTAMP + ON UPDATE CURRENT_TIMESTAMP(MySQL),简单但灵活度低;
  • 应用层填充:MyBatis-Plus 提供 MetaObjectHandler,在插入/更新前统一赋值:
@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());
    }
}

配合实体字段声明填充时机:

@TableField(fill = FieldFill.INSERT)        // 仅插入时填充
private LocalDateTime createTime;
@TableField(fill = FieldFill.INSERT_UPDATE) // 插入与更新都填充
private LocalDateTime updateTime;

纯 MyBatis 没有现成填充钩子,常见做法是 Service 层统一 set,或用拦截器/ThreadLocal 注入当前时间。

两个提醒:逻辑删除列慎建唯一索引——记录被删后同名数据将无法再次插入;时间字段建议"DB 默认值 + 应用填充"双保险,防止漏走框架路径的直写 SQL 产生空值。

逻辑删除解决"删得掉又找得回",公共字段填充解决"每张表都写的样板代码"。小项目手写约定即可,上了 MP 就用 @TableLogic 与 MetaObjectHandler,注意唯一索引与时区两个隐藏坑。

笔记加载中…