再见,物理删除!MyBatis-Plus @TableLogic 优雅实现逻辑删除

在开发应用程序时,我们经常会遇到需要删除数据的场景。但直接从数据库中物理删除(DELETE​)数据有时并非最佳选择。为什么呢?

  • 数据恢复: 一旦物理删除,数据通常难以恢复,误操作可能导致灾难性后果。
  • 审计追踪: 很多业务场景需要保留操作记录,包括删除记录。
  • 数据关联: 物理删除可能破坏与其他表的关联关系,导致数据不一致或需要复杂的级联删除策略。

这时,逻辑删除就成了一个非常优雅的解决方案。逻辑删除并非真的从数据库移除数据,而是通过一个特定的字段(例如 deleted​、is_deleted​)来标记记录的状态,将其标记为“已删除”。在应用程序层面,这些被标记的数据通常表现为“不存在”,但在数据库层面,它们仍然保留着。

手动实现逻辑删除通常意味着:

  1. 将所有的 DELETE​ 操作改为 UPDATE ... SET deleted = 1 ...​。
  2. 在所有的 SELECT​ 查询中,手动添加 WHERE deleted = 0​ 的条件。

这无疑会增加大量重复代码,且容易遗漏,维护起来也相当痛苦。幸运的是,强大的 MyBatis-Plus (MP) 框架为我们提供了 @TableLogic​ 注解,让实现逻辑删除变得极其简单和自动化。

什么是 @TableLogic​?

​@TableLogic​ 是 MyBatis-Plus 提供的一个注解,用于标记实体类中代表逻辑删除状态的字段。一旦配置完成,MP 会在底层通过拦截器自动处理逻辑删除相关的 SQL 转换。

如何使用 @TableLogic​?

使用 @TableLogic​ 非常简单,只需三步:

第一步:数据库表设计

在需要支持逻辑删除的表中,添加一个用于标记删除状态的字段。通常使用 TINYINT​、INT​ 或 BOOLEAN​ 类型。例如,我们添加一个 deleted​ 字段:

ALTER TABLE `your_table_name`
ADD COLUMN `deleted` tinyint(1) UNSIGNED NOT NULL DEFAULT 0 COMMENT '逻辑删除标记(0:未删除; 1:已删除)';-- 为该字段添加索引通常是个好主意,特别是当已删除数据量较大时
ALTER TABLE `your_table_name` ADD INDEX `idx_deleted` (`deleted`);

第二步:实体类配置

在对应的 Java 实体类中,添加该字段,并使用 @TableLogic​ 注解标记它:

import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;@Data
@TableName("your_table_name")
public class YourEntity {private Long id;private String name;// ... 其他字段@TableLogic // 标记为逻辑删除字段private Integer deleted; // 字段类型与数据库对应
}
  • ​@TableLogic​ 注解本身就足以启用逻辑删除功能。

第三步:全局配置 (application.yml/properties)

虽然 @TableLogic​ 注解本身已经能工作,但最佳实践是在项目的配置文件中指定全局的“未删除值”和“已删除值”。这样 MP 就知道在生成 SQL 时应该用哪些具体的值。

mybatis-plus:global-config:db-config:# 逻辑删除字段名(如果实体类中字段名就是这个,可以省略,但推荐写上保持清晰)# 注意:即使配置了全局字段名,实体类中仍然需要 @TableLogic 注解来 *标识* 哪个字段是逻辑删除字段logic-delete-field: deleted# 逻辑已删除值(默认为 1)logic-delete-value: 1# 逻辑未删除值(默认为 0)logic-not-delete-value: 0

如果你的逻辑删除字段名、已删除值、未删除值与全局配置不同,也可以在 @TableLogic​ 注解中单独指定:

// 假设用 status 字段,0表示正常,-1表示删除
@TableLogic(value = "0", delval = "-1")
private Integer status;

但通常建议保持全局一致性。

@TableLogic​ 如何工作?

配置完成后,MP 内置的 LogicSqlInnerInterceptor​(需要通过 MybatisPlusInterceptor​ 注册)就会自动生效:

  1. 对于删除操作: 当你调用 BaseMapper​ 提供的标准删除方法时,例如:

    yourMapper.deleteById(1L);
    // 或者
    yourMapper.removeById(1L);
    

    MP 不会执行物理 DELETE​。它会自动将 SQL 转换为:

    UPDATE your_table_name SET deleted = 1 WHERE id = 1 AND deleted = 0;
    

    它只会将当前状态为“未删除”(deleted = 0​) 的记录标记为“已删除”(deleted = 1​)。

  2. 对于查询操作: 当你调用 BaseMapper​ 提供的所有标准查询方法时,例如:

    YourEntity entity = yourMapper.selectById(1L);
    List<YourEntity> list = yourMapper.selectList(null); // 查询所有
    IPage<YourEntity> page = yourMapper.selectPage(pageParam, wrapper);
    // ...等等
    

    MP 会自动在这些查询的 WHERE​ 子句后面(或 WHERE​ 子句内,如果没有其他条件)追加逻辑删除的过滤条件:

    -- selectById(1L) 可能的 SQL
    SELECT id, name, deleted /*, ...*/ FROM your_table_name WHERE id = 1 AND deleted = 0;-- selectList(null) 可能的 SQL
    SELECT id, name, deleted /*, ...*/ FROM your_table_name WHERE deleted = 0;-- selectPage(page, wrapper) 可能的 SQL (假设 wrapper 有其他条件)
    SELECT id, name, deleted /*, ...*/ FROM your_table_name WHERE name LIKE '%test%' AND deleted = 0 LIMIT ?, ?;
    

    这意味着,通过标准方法查询时,你永远只会得到未被逻辑删除的数据。

如何查询包含已删除的数据?

这是一个常见需求,比如在后台管理界面需要查看回收站内容,或者进行数据恢复操作。

既然 MP 的标准查询方法会自动添加 AND deleted = 0​ 的限制,那么要查询包含已删除的数据(甚至只查询已删除的数据),我们就必须绕过这个自动行为。

方法就是:使用自定义 SQL (在 Mapper XML 文件中)。

  1. 在 Mapper 接口定义方法:

    public interface YourMapper extends BaseMapper<YourEntity> {// 查询指定 ID 的记录,无论其删除状态YourEntity selectByIdIncludeDeleted(@Param("id") Long id);// 查询所有已删除的记录List<YourEntity> selectDeletedList();
    }
    
  2. 在 Mapper XML 文件中编写 SQL:

    <mapper namespace="com.yourpackage.mapper.YourMapper"><resultMap id="BaseResultMap" type="com.yourpackage.domain.YourEntity"><!-- ... 字段映射 ... --><result column="deleted" property="deleted"/></resultMap><select id="selectByIdIncludeDeleted" resultMap="BaseResultMap">SELECT id, name, deleted /*, ...*/FROM your_table_nameWHERE id = #{id}<!-- 注意:这里我们没有写 deleted = 0 条件,MP 也不会自动加 --></select><select id="selectDeletedList" resultMap="BaseResultMap">SELECT id, name, deleted /*, ...*/FROM your_table_nameWHERE deleted = 1 <!-- 手动指定查询已删除的数据 --></select>
    </mapper>
    

    关键在于:对于 XML 中手写的 SQL,MP 的逻辑删除拦截器不会去修改它,也不会自动追加 deleted​ 条件。你可以完全控制查询逻辑。

@TableLogic​ 的优势

  • 代码简洁: 无需在业务代码中重复编写 deleted = 0​ 的查询条件和 UPDATE​ 式的删除逻辑。
  • 不易出错: 自动化处理减少了手动编码时遗漏条件的风险。
  • 全局一致: 保证了整个应用处理逻辑删除行为的一致性。
  • 低侵入性: 对业务代码的侵入非常小,主要通过注解和配置完成。

注意事项

  • 性能: 如果逻辑删除的数据量非常大,查询性能可能会受到影响。确保在逻辑删除字段上建立了索引。考虑定期归档或物理清除不再需要的已删除数据。
  • 唯一约束: 如果表中有唯一约束,逻辑删除可能导致问题(例如,用户注销账号后,其邮箱被标记为删除,但新用户无法使用该邮箱注册,因为唯一约束仍然存在)。需要根据业务场景设计合适的处理策略。

总结

MyBatis-Plus 的 @TableLogic​ 为 Java 应用实现逻辑删除提供了一个极其便捷和强大的解决方案。它通过简单的注解和配置,将开发者从繁琐、重复的 SQL 处理中解放出来,让我们能更专注于业务逻辑本身。掌握并使用好 @TableLogic​,无疑能提升代码质量和开发效率,构建更健壮、更易于维护的应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/903303.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

湖北理元理律师事务所:债务管理领域的平台化创新探索

随着中国居民负债率攀升至62%&#xff08;央行2023年数据&#xff09;&#xff0c;债务管理从个体需求演变为社会性课题。湖北理元理律师事务所通过“法律科技金融”的融合模式&#xff0c;构建了国内首个全链条债务管理平台&#xff0c;其服务逻辑与行业价值值得深度剖析。 平…

【更新】LLM Interview (2)

字数溢出&#xff0c;不解释 前文&#xff1a;llm interview (1) 文章目录 强化学习专题1 什么是RL&#xff1f;2 RL和监督、非监督、深度学习的区别3 RL中所谓的损失函数与深度学习中的损失函数有何区别&#xff1f;4 RL历史5 RL分类5.1 分类图示5.2 根据智能体动作选取方式分…

高性价比手机如何挑选?

这四个关键点&#xff0c;助你找到心仪机~ 一、性能强者&#xff1a;游戏娱乐畅快到底 处理器相当于手机的 “大脑”&#xff0c;处理速度快、能力强&#xff0c;运行大型游戏毫无压力。 搭配上大容量运存&#xff0c;多任务切换也能秒速完成&#xff0c;再也不怕游戏卡顿啦。…

测试—概念篇

1. 什么是需求 在多数软件公司&#xff0c;会有两部分需求&#xff0c;⼀部分是用户需求&#xff0c;⼀部分是软件需求。 1.1 用户需求 用户需求&#xff1a;可以简单理解为甲方提出的需求&#xff0c;如果没有甲方&#xff0c;那么就是终端用户使⽤产品时必须要完成的任务。…

HTML5好看的水果蔬菜在线商城网站源码系列模板7

文章目录 1.设计来源1.1 主界面1.2 关于我们界面1.3 商城界面1.4 商品信息界面1.5 我的账户界面1.6 联系我们界面 2.效果和源码2.1 动态效果2.2 源代码 源码下载万套模板&#xff0c;程序开发&#xff0c;在线开发&#xff0c;在线沟通 作者&#xff1a;xcLeigh 文章地址&#…

Atcoder Help 有关Atcoder 的介绍-1 涨分规则

AtCoder 的 Rating 计算系统基于改进的 Elo 算法&#xff0c;主要包含以下核心机制&#xff1a; 一、基础计算公式 Rating 是「表现分(Performance)」的加权平均值减去衰减函数 f ( n ) f(n) f(n)&#xff0c;其中&#xff1a; 新用户初始 f ( 1 ) 1200 f(1)1200 f(1)120…

设置右键打开VSCode

在日常的开发工作中&#xff0c;VSCode 是一款非常受欢迎的代码编辑器。为了更加便捷地使用它&#xff0c;我们可以将 VSCode 添加到右键菜单中&#xff0c;这样只需右键点击文件或文件夹&#xff0c;就能快速用 VSCode 打开&#xff0c;极大地提高工作效率。下面我就来介绍一下…

python密码学之密钥HSM硬件抽象层(HAL)

目录 摘要1. 项目背景与总体架构1.1 HSM 与 HAL 的必要性1.2 本项目目标1.3 模块化设计2. 自研轻量对称加密算法 SSC(SimpleSecureCipher)2.1 算法原理2.2 轮密钥扩展3. HAL 接口与安全内存模拟3.1 HAL 接口定义3.2 安全内存 SecureMemory4. PyQt6 GUI 设计与功能模块4.1 界面…

机器学习分类模型性能评估:应对类别不平衡的策略与指标

在机器学习的世界里&#xff0c;模型们就像一群努力破案的侦探&#xff0c;而数据就是它们的“犯罪现场”。今天&#xff0c;咱们的主角——一个自命不凡的分类模型&#xff0c;接到了一个看似简单的任务&#xff1a;揪出那些患有罕见疾病的患者。这听起来是不是很容易&#xf…

vue3代码规范管理;基于vite和vue3、 eslint、prettier、stylelint、husky规范;git触发eslint校验

前言 为提高前端代码格式化和规范开发。主要使用eslint、prettier、husky完成对git提交commit信息校验和代码eslint格式化校验&#xff0c;不符合要求的代码&#xff0c;提交不到仓库。 参考链接1 参考链接2 文章目录 前言一、效果图1.git提交触发eslint规范校验2.版本与分支名…

GCC 内建函数汇编展开详解

1. 引言 GNU 编译器集合&#xff08;GCC&#xff09;是广泛使用的开源编译器套件&#xff0c;支持多种编程语言&#xff0c;其中 C 语言编译器是其核心组件之一。在 C 语言编译过程中&#xff0c;GCC 不仅处理用户编写的标准 C 代码&#xff0c;还提供了一类特殊的函数——内建…

uniapp利用生命周期函数实现后台常驻示例

在 Uniapp 中&#xff0c;利用生命周期函数实现“后台常驻”主要是通过监听应用的前后台状态变化&#xff08; onHide 和 onShow &#xff09;&#xff0c;并结合 定时器、后台任务或状态保持逻辑 来实现。但需注意&#xff1a; 纯前端 JS 代码无法突破系统对后台应用的限制&am…

layui时间范围

//时间范围String time_range para.getString("time_range", "");if (!StrUtil.isEmpty(time_range)) {String dateArr[] time_range.split("-");if (dateArr.length 2) {para.put("start_date", dateArr[0].trim().replace("…

入门版 鸿蒙 组件导航 (Navigation)

入门版 鸿蒙 组件导航 (Navigation) 注意&#xff1a;使用 DevEco Studio 运行本案例&#xff0c;要使用模拟器&#xff0c;千万不要用预览器&#xff0c;预览器看看 Navigation 布局还是可以的 效果&#xff1a;点击首页&#xff08;Index&#xff09;跳转到页面&#xff08…

VUE3:封装一个评论回复组件

之前用React封装的评论回复组件&#xff0c;里面有三个主要部分&#xff1a;CommentComponent作为主组件&#xff0c;CommentItem处理单个评论项&#xff0c;CommentInput负责输入框。现在需要将这些转换为Vue3的组件。 Vue3和React在状态管理上有所不同&#xff0c;Vue3使用r…

制作一款打飞机游戏27:精灵编辑器UI

继续开发我们的编辑器——Sprit Edit。我们已经创建了这个小编辑器&#xff0c;它可以显示很多精灵&#xff08;sprites&#xff09;&#xff0c;并且我们可以遍历所有精灵。这真的很棒&#xff0c;我们可以创建新的精灵&#xff0c;这也不错。但是&#xff0c;唉&#xff0c;我…

k8s(9) — zookeeper集群部署(亲和性、污点与容忍测试)

一、部署思路 1、前期设想 zookeeper集群至少需要运行3个pod集群才能够正常运行&#xff0c;考虑到节点会有故障的风险这个3个pod最好分别运行在&#xff13;个不同的节点上(为了实现这一需要用到亲和性和反亲和性概念)&#xff0c;在部署的时候对zookeeper运行的pod打标签加…

WXT+Vue3+sass+antd+vite搭建项目开发chrome插件

WXTVue3sassantdvite搭建项目开发chrome插件 前言一、初始化项目二、项目配置调整三、options页面配置四、集成antd五、集成sass六、环境配置七、代码注入 vue3&#xff1a;https://cn.vuejs.org/ axios&#xff1a;https://www.axios-http.cn/docs/api_intro antd&#xff1a;…

JSAPI2.4——正则表达式

一、语法 const str 一二三四五六七八九十 //判断内容 const reg /二/ //判断条件 console.log(reg.test(str)); //检查 二、test与exec方法的区别 test方法&#xff1a;用于判断是否符合规则的字符串&#xff0c;返回值是布尔值 exec方法&…

燃气用户检修工考试精选题

燃气用户检修工考试精选题&#xff1a; 我国国家标准规定民用天然气中硫化氢含量最高允许浓度是&#xff08; &#xff09;。 A. 20mg/m B. 15mg/m C. 5mg/m D. 50mg/m 答案&#xff1a;A 城市燃气应具有可以察觉的臭味&#xff0c;当无毒燃气泄漏到空气中&#xff0c;达到爆炸…