news 2026/4/15 18:10:08

MyBatisPlus逻辑删除:保留用户已删除的修复任务历史记录

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MyBatisPlus逻辑删除:保留用户已删除的修复任务历史记录

MyBatisPlus逻辑删除:保留用户已删除的修复任务历史记录

在构建一个面向用户的图像修复系统时,我们常常面临这样一个矛盾:用户希望“删除”某个任务来清理界面,但系统又必须保留这些操作的历史痕迹,以便后续审计、分析或恢复。尤其是在像老照片智能修复这类涉及数字资产留存的场景中,一次误删可能意味着永久丢失珍贵的处理记录。

这正是逻辑删除大显身手的地方。

DDColor 黑白老照片智能修复系统为例,每当用户上传一张黑白照片并启动修复流程,系统都会生成一条修复任务记录。无论这张照片是祖辈的合影,还是早已消失的老建筑影像,其修复过程本身就是一段值得保存的数字足迹。即便用户后来点击了“删除”,我们也绝不能真正将其从数据库中抹去——而 MyBatisPlus 的逻辑删除机制,恰好为我们提供了一种优雅且高效的解决方案。


为什么选择逻辑删除?

物理删除就像把文件扔进碎纸机,再也拼不回来;而逻辑删除更像是给文件贴上“已归档”标签,它依然存在,只是不再出现在常规视野中。这种模式在现代应用开发中已成为标配,尤其适用于需要数据追溯、合规审计或防误操作的系统。

MyBatisPlus 对逻辑删除的支持并非简单的字段标记,而是一整套贯穿 CRUD 操作的自动化拦截机制。你不需要手动拼接WHERE deleted = 0,也不必重写删除方法,只需通过注解和配置,框架就会自动完成以下转换:

  • 执行removeById(id)时,实际执行的是UPDATE repair_task SET deleted = 1 WHERE id = ? AND deleted = 0
  • 查询列表时,默认自动追加AND deleted = 0,确保不会拉出已删除的数据
  • 插入和更新操作则完全不受影响,保持原有语义不变

这一切的背后,是由LogicDeleteInnerInterceptor实现的 SQL 重写能力。它作为 MyBatisPlus 拦截器链的一部分,在 SQL 构建阶段动态注入逻辑删除条件,真正做到无侵入、低耦合。

实体设计:让删除变得“可逆”

RepairTask实体类中,我们只需要添加一个字段并标注@TableLogic

@Data @TableName("repair_task") public class RepairTask { private Long id; private String userId; private String imageUrl; private String taskType; // PERSON / BUILDING private LocalDateTime createTime; private LocalDateTime updateTime; @TableLogic private Integer deleted; // 0: 正常, 1: 已删除 }

这个deleted字段就是逻辑删除的核心开关。默认情况下,MyBatisPlus 会将0视为未删除,1视为已删除。当然,你也可以自定义映射规则,比如使用布尔值(false/true)或者字符串(”N”/”Y”),只需配合全局处理器即可。

配置即生效:一行代码开启软删能力

为了让整个系统支持逻辑删除,我们需要注册对应的拦截器:

@Configuration @MapperScan("com.example.mapper") public class MyBatisPlusConfig { @Bean public MybatisPlusInterceptor mybatisPlusInterceptor() { MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); interceptor.addInnerInterceptor(new LogicDeleteInnerInterceptor()); return interceptor; } }

就这么简单。一旦注册成功,所有带有@TableLogic注解的实体都将自动启用软删功能。无需修改任何业务代码,原有的save()removeById()list()等方法依然照常调用,底层却已经悄然完成了语义转换。

⚠️ 小贴士:如果你有多个数据源或特殊字段类型需求,还可以实现ILogicDeleteHandler来定制不同字段的删除值映射逻辑。

查询控制:谁能看到“回收站”里的数据?

普通用户调用查询接口时,理应只能看到自己尚未删除的任务。得益于 MyBatisPlus 的自动过滤机制,以下代码天然具备此特性:

public List<RepairTask> listActiveTasks(String userId) { return this.lambdaQuery() .eq(RepairTask::getUserId, userId) .list(); }

生成的 SQL 会自动变成:

SELECT * FROM repair_task WHERE user_id = ? AND deleted = 0

但如果管理员需要查看“回收站”中的内容呢?这时就需要绕过默认过滤。最直接的方式是使用.last()方法强行加入条件:

public List<RepairTask> listAllIncludingDeleted(String userId) { return this.lambdaQuery() .eq(RepairTask::getUserId, userId) .last("OR deleted = 0 OR deleted = 1") .list(); }

虽然有效,但.last()属于原生 SQL 拼接,存在一定的安全风险。更推荐的做法是显式指定deleted字段的查询范围:

.eq(RepairTask::getDeleted, 0).or().eq(RepairTask::getDeleted, 1)

或者封装一个专用的“包含已删除”查询构造器,避免在多处重复编写逻辑。


图像修复背后的流水线:ComfyUI + DDColor 工作流

如果说逻辑删除保障了数据层面的可追溯性,那么 ComfyUI 与 DDColor 模型的结合,则让 AI 图像修复变得触手可及。

DDColor 是一种专为黑白图像着色设计的深度学习模型,能够在保留原始结构的基础上,智能还原色彩信息。它并不依赖复杂的参数调整,而是通过预设的工作流(Workflow)来标准化处理流程。这些工作流以 JSON 文件形式存在,本质上是一组节点连接图,描述了从图像输入到结果输出的完整路径。

例如,人物修复与建筑修复对分辨率的要求截然不同:

  • 人物修复更注重肤色自然度和面部细节,适合使用中等分辨率(460–680),避免过度渲染导致失真;
  • 建筑修复则需展现丰富的纹理和轮廓,通常采用更高分辨率(960–1280),确保砖瓦、窗户等元素清晰可见。

为此,系统提供了两个独立的 JSON 工作流文件:

  • DDColor人物黑白修复.json
  • DDColor建筑黑白修复.json

每个文件内部都封装了最优参数组合,用户无需了解模型原理,只需选择对应类型并上传图片,即可一键完成高质量修复。

工作流长什么样?

以下是简化后的人物修复流程关键节点:

{ "nodes": [ { "id": 1, "type": "LoadImage", "widgets_values": ["input.png"] }, { "id": 2, "type": "DDColor_Preprocessor", "inputs": [[1, "IMAGE"]], "widgets_values": [460] }, { "id": 3, "type": "DDColor_Ddcolorize", "inputs": [[2, "IMAGE"]], "widgets_values": ["ddcolor_realv1", 460] }, { "id": 4, "type": "SaveImage", "inputs": [[3, "IMAGE"]], "widgets_values": ["output"] } ] }

整个流程仅四个节点:
1. 加载图像;
2. 预处理并调整尺寸至 460;
3. 调用ddcolor_realv1模型进行着色;
4. 保存结果。

用户甚至可以修改widgets_values中的模型名称或分辨率,快速尝试不同效果。前提是本地已下载相应权重文件,否则会因找不到模型而报错。

⚠️ 实践建议:
- 在部署环境统一管理模型版本,避免因缺失文件导致任务失败;
- 启动前校验工作流节点连接完整性,防止中间断连;
- 对高频使用的参数组合做缓存或模板化处理,提升响应速度。


系统如何协同工作?

从前端用户操作到后台数据存储,再到 GPU 推理执行,整个系统的协作链条如下:

[前端 Web 页面] ↓ (上传图像 + 选择任务类型) [Spring Boot 后端服务] ├── 记录修复任务 → MyBatisPlus 持久化 → MySQL(含逻辑删除字段) └── 触发图像处理 → 调用 ComfyUI API 执行 DDColor 工作流 ↓ [GPU 服务器运行推理] ↓ 返回修复结果图像

每一步都有明确职责:
- 用户发起请求后,后端立即创建一条repair_task记录,状态为deleted=0
- 任务异步提交至 ComfyUI,利用 GPU 加速完成图像修复;
- 结果返回后更新任务记录,包含输出链接和处理耗时;
- 用户可在“我的任务”中查看所有未删除任务;
- 当用户点击“删除”,系统调用removeById(id),该记录的deleted字段被置为1,前端不再展示;
- 管理员可通过后台接口查询全部记录,包括已被“删除”的任务。

这套机制既尊重了用户的操作习惯,又保证了数据的完整性与安全性。


设计背后的关键考量

1. 字段命名与类型统一

我们坚持使用deleted作为逻辑删除字段名,类型为INT,取值0/1。这不是随意决定的,而是出于团队协作和长期维护的考虑:

  • 统一命名降低理解成本,新人接手也能快速识别;
  • 使用整型而非布尔型,兼容更多数据库类型(如 Oracle 不支持 BOOLEAN);
  • 易于扩展未来可能的状态(如2=归档、3=审核中)。

2. 性能优化:别忘了给deleted加索引

随着数据量增长,WHERE deleted = 0这类查询将成为性能瓶颈。因此,务必在deleted字段上建立索引:

ALTER TABLE repair_task ADD INDEX idx_deleted (deleted);

对于复合查询(如按用户 + 状态筛选),还可创建联合索引进一步提升效率:

ALTER TABLE repair_task ADD INDEX idx_user_deleted (user_id, deleted);

3. 数据生命周期管理:定期归档,释放压力

尽管逻辑删除保留了历史,但也带来了数据膨胀的问题。我们制定了如下策略:

  • 所有deleted=1且超过 6 个月的任务,自动迁移至repair_task_history历史表;
  • 主表仅保留最近两年的有效数据,保障查询性能;
  • 历史表可离线备份或迁移到低成本存储介质。

这一过程可通过定时任务(如 Quartz 或 XXL-JOB)驱动,结合分页批量迁移,避免一次性加载过多数据造成内存溢出。

4. 权限隔离:普通人看不见“回收站”,管理员可以

前端默认只请求未删除任务,这是用户体验的基本要求。但后台管理系统应提供“查看已删除任务”的功能,供运营或技术支持人员排查问题。

实现上可通过两种方式区分权限:
- 接口层面:普通用户走/api/tasks,管理员走/admin/tasks?includeDeleted=true
- 服务层判断:根据当前登录角色决定是否忽略deleted条件

同时建议配合操作日志系统,记录每一次“删除”行为的时间、IP、用户ID等信息,形成完整的审计轨迹。

5. 工作流也要版本控制

JSON 工作流文件虽小,却是核心资产。我们将其纳入 Git 版本管理,并遵循以下规范:

  • 每次参数调优都提交新版本,附带变更说明;
  • 生产环境只允许使用 tagged 的稳定版本;
  • 支持按任务类型动态加载对应工作流,便于灰度发布。

这样即使某次更新引入 Bug,也能迅速回滚至上一版本,最大限度减少影响。


写在最后

技术的价值,往往体现在那些“看不见的地方”。

MyBatisPlus 的逻辑删除看似只是一个小小的注解,但它守护的是用户每一次操作的真实轨迹;DDColor 工作流看似只是一串 JSON 配置,但它降低了 AI 技术的使用门槛,让更多人能亲手唤醒尘封的记忆。

在这个系统中,我们没有追求炫酷的功能堆叠,而是专注于两个朴素的目标:
-不让任何一次修复被真正抹去
-不让任何一个用户被技术吓退

而这,或许才是真正的“智能”所在。

当一位老人看着修复后的全家福热泪盈眶时,他不会关心背后用了什么 ORM 框架,也不会在意是不是逻辑删除保住了那条任务记录。但他知道,这张照片回来了——这就够了。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/16 10:41:19

League Akari智能游戏助手:新手玩家的高效游戏解决方案

League Akari智能游戏助手&#xff1a;新手玩家的高效游戏解决方案 【免费下载链接】LeagueAkari ✨兴趣使然的&#xff0c;功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 在英雄联…

作者头像 李华
网站建设 2026/4/16 12:26:35

手把手教你实现简单的推荐系统算法

从零构建推荐系统&#xff1a;协同过滤与相似度计算实战你有没有想过&#xff0c;为什么抖音总能“猜中”你喜欢的视频&#xff1f;为什么淘宝刚浏览过的商品&#xff0c;第二天就在首页弹出来&#xff1f;这背后不是魔法&#xff0c;而是推荐系统在默默工作。在今天这个信息爆…

作者头像 李华
网站建设 2026/4/16 12:22:06

避免重复造轮子:直接使用现成DDColor镜像节省开发时间

避免重复造轮子&#xff1a;直接使用现成DDColor镜像节省开发时间 在数字档案修复、家庭老照片翻新甚至影视资料复原的日常工作中&#xff0c;一个看似简单却极其耗时的问题始终困扰着从业者——如何快速、真实地为黑白影像上色&#xff1f;过去&#xff0c;这需要专业美术人员…

作者头像 李华
网站建设 2026/4/16 12:20:52

2025 AI Coding实践总结 - AI Coding工具真的好用吗?

2025年是AI飞速发展的一年&#xff0c;从年初的DeepSeek R1到年末ChatGpt-5.2&#xff0c;模型在复杂推理&#xff0c;agentic能力上持续跃升。依托大模型能力的提升&#xff0c;Agent在更多场景开始逐步实现工程化落地&#xff0c;2025年也称得上Agent元年(Manus在昨天被meta收…

作者头像 李华
网站建设 2026/4/16 12:24:25

英雄联盟智能助手终极攻略:从入门到精通的完整指南

英雄联盟智能助手终极攻略&#xff1a;从入门到精通的完整指南 【免费下载链接】LeagueAkari ✨兴趣使然的&#xff0c;功能全面的英雄联盟工具集。支持战绩查询、自动秒选等功能。基于 LCU API。 项目地址: https://gitcode.com/gh_mirrors/le/LeagueAkari 在快节奏的英…

作者头像 李华