MySQL逻辑删除+Mybatis-Plus = 墙裂推荐

news2024/10/6 12:20:08

目录

  • 前言
  • 逻辑删除
  • 使用Mybatis-Plus逻辑删除
    • 它做了什么
  • 注意
  • 写在后面的一些话

06029e728d1f48fdf5ddd405f65693fc

前言

一般情况下,我们要删除一条数据,直接使用 delete 即可,就像这样:delete from user where id = 1,这样做的好处是:

  • 符合我们的理解,删除就是直接删掉嘛。
  • 节省数据库空间,某些情况下数据量较大,且新增和删除比较频繁时,delete可以帮我们回收很多的空间。

但我今天想讲的是逻辑删除,那什么是逻辑删除呢?

逻辑删除

逻辑删除就是给数据表添加一个固定字段,用该字段的值来表示这条数据当前是否被删除,并把 delete 操作修改为 update 操作。

比如,在我的项目中某些表会有一个固定的 is_deleted 字段,该字段是 tinyint 型的,其取值只有 0 和 1 两种,0表示这条数据未删除,1表示已删除,默认值为 0。

当我要删除某条数据时,我会将这条数据的 is_deleted 值置为 1,而不会使用 delete 去真正的把它删掉。同时,我的所有 insert 语句和 update 语句都会带上一个固定的条件 is_deleted = 0 ,来过滤掉所有在逻辑上被删除的数据。

image-20230114151004431

△图 / 校园博客用户表数据

同样的,也来讲讲这样做的好处:

  • 方便数据恢复,保护数据本身的价值。
  • 保证数据连续性,对主键的影响可能会导致底层B+树重建,而 delete 和 update id 都会影响主键。

事实上,在大多数公司里,都会采用逻辑删除的方式,因为数据的价值更大,被删除的数据也非常有记录价值,这样的操作也并不会提高太多的操作难度。

使用Mybatis-Plus逻辑删除

如果你的项目使用的是Mybatis-Plus框架来操作数据库,那你可以通过下面几个步骤快速的转变到逻辑删除模式。

  1. 在MySQL中给那些要改为逻辑删除的表添加一个 is_deleted 字段,当然也可以叫 flag 或者是别的名字,只要你喜欢就好。类型 tinyint 就够了,默认值最好也设置一下。

    -- 你也可以直接使用这条修改语句,记得把表名进行替换
    ALTER TABLE user ADD `is_deleted` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT '0为未删除,1为已删除';
    
  2. 在你的Java代码中给刚刚修改过的表的实体类添加对应的属性:

    public class User {
    	// 添加isDeleted字段
        Integer isDeleted;
    }
    
  3. 在项目的配置文件(application.yml)当中添加对应的配置:

    mybatis-plus:
      global-config:
        db-config:
          logic-delete-field: isDeleted # 全局逻辑删除的实体字段名
          logic-delete-value: 1 # 逻辑已删除值(默认为 1)
          logic-not-delete-value: 0 # 逻辑未删除值(默认为 0)
    
  4. 如果你的Mybatis-Plus版本在 3.3.0 以下,那你还需要在实体类的字段上添加 @TableLogic 注解:

    @TableLogic
    Integer isDeleted;
    
  5. 如果你的项目中有通过xml或者@Update@Select等注解编写的SQL语句,那你需要自己对他们进行调整:

    • 将原有的 delete 语句统一修改为 update
    • 将原有的 select、update 语句都加一个过滤条件 is_deleted = 0
    • insert 语句,如果你在表上设置了默认值的话,则可以不用管它。如果你没有设置默认值,那我建议你还是设置一下😎。

好了就这么简单,你甚至不需要修改你的业务代码,因为Mybatis-Plus已经帮你处理好了。

它做了什么

  • 当你调用userMapper.deleteById(1)的时候,实际上传到MySQL的代码是这样的:

    update user set is_deleted = 1 where id = 1 and is_deleted = 0
    
  • 当你通过QueryWrapper查询数据或者通过 UpdateWrapper 更新数据的时候,它也会自动帮你添加过滤条件:

    select * from user where is_deleted = 0
    
  • 但如果你是在xml中直接写的SQL语句,那它是不会帮你进行修改的,比如我写的SQL是这样的:

    <update id="deleteById">
        update user
        set is_deleted = ${id}
        where id = ${id}
    </update>
    

    执行出来的SQL是这样的:

    image-20230114215203805

    很显然它并没有帮我加上 is_deleted = 0 ,这是使用者需要注意的。

当然我只是简单的对Mybatis-Plus的逻辑删除功能用法进行了简单讲解,如果你需要的话,也可以参考一下官方文档的说明:逻辑删除 | MyBatis-Plus (baomidou.com) (虽然它写的也比较简洁👨‍💻)

注意

虽然把项目过渡到逻辑删除并不太费事,但它也有一些其他需要注意的点。

首先是使用理念上,我这里直接引用 Mybatis-Plus 的说法:

  • 逻辑删除是为了方便数据恢复和保护数据本身价值等等的一种方案,但实际就是删除。
  • 如果你需要频繁查出来看就不应使用逻辑删除,而是以一个状态去表示。

其次是使用逻辑上,对于MySQL而言,逻辑删除会导致唯一索引(UNIQUE KEY)的异常。

  • 原因很简单,已经删除的数据仍然存在,当再次插入一条同样的数据时,就会抛出异常。

  • 比如在我的 user 表中 username 字段设置了 UNIQUE KEY ,我先插入一条username = 阿杆的数据,再把这条数据逻辑删除掉,然后再重新插入一条username = 阿杆的数据。

    那么理论上来说此时是应该允许插入的,但由于我使用了逻辑删除,MySQL不允许存在两条数据出现同样的 username = 阿杆的场景,此时就出现了异常。

  • 当然,逻辑删除与唯一索引的冲突是可以解决的,解决方案也不难。

    我们可以在原来的唯一索引里加上is_deleted字段,同时再删除数据的时候把is_deleted修改为表id,这样就可以保证未删除的数据不会出现重复值了,而且不会受到已删除数据的影响。但你要记得重写SQL方法,不然Mybatis-Plus还是会帮你修改为配置文件里的那个默认值。

    UNIQUE KEY `username` (`username`,`is_deleted`) USING BTREE
    

    方案不唯一,你也可以用别的方法,或者在这张表上不使用逻辑删除,毕竟,没有最好的,只有最合适的。

写在后面的一些话

本文是我在使用Mybatis-Plus将项目过渡到逻辑删除时写的,也算是刚接触逻辑删除这个东西,可能会有一些考虑不周全的地方,希望各位大佬在评论区提出。

另外,如果你想找一个项目参考一下逻辑删除的具体代码或者过渡方案,可以来看看我的校园博客项目,也可以看看我过渡时修改的代码,这几个PR就是我修改的全部代码了:

  • 大部分修改的内容:Dev 126 数据库表结构优化 by stick-i · Pull Request #132 · stick-i/scblogs (github.com)
  • 与业务代码有关的bug:chore: 给user_view添加is_deleted字段(由于其继承自user表) by stick-i · Pull Request #133 · stick-i/scblogs (github.com)
  • 唯一索引与逻辑删除造成异常的解决:fix: 处理user表和user_safety表的唯一索引和逻辑删除造成的冲突。 by stick-i · Pull Request #134 · stick-i/scblogs (github.com)

也欢迎大家来参与项目贡献或者star😋,项目地址:https://github.com/stick-i/scblogs

6f88c1e56daebed179cbf337712b611b

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

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

相关文章

C进阶_字符串库函数

目录 求字符串长度 strlen 常规实现 递归实现 指针-指针实现 长度不受限制的字符串函数 strcpy 模拟实现strcpy strcat 模拟实现strcat strcmp 模拟实现strcmp 长度受限制的字符串函数 strncpy strncat strncmp 求字符串长度 strlen size_t strlen ( const c…

前端工具(运用造型)

CSS预处理器的使用方法 1、什么是css预处理器 CSS预处理器是一种专门的编程语言&#xff0c;用来为CSS增加一些编程特性&#xff08;CSS本身不是编程语言&#xff09;不需要考虑浏览器兼容问题&#xff0c;因为CSS预处理器最终编译和输出的仍是标准的CSS样式。可以在CSS预处理…

磨金石教育摄影技能干货分享|简述特效在影视制作中的四大作用

近三年因为疫情的原因&#xff0c;极少去影院去看电影。 想起来上次看电影还是去年八月份&#xff0c;当时上映的是科幻大作《沙丘》。看科幻电影&#xff0c;最大的期待就是导演编剧们对外星球与外太空场景的塑造。那些逼真的场景与炫酷的战舰航天器&#xff0c;满足了我对未知…

设计模式_结构型模式 -《适配器模式》

设计模式_结构型模式 -《适配器模式》 笔记整理自 黑马程序员Java设计模式详解&#xff0c; 23种Java设计模式&#xff08;图解框架源码分析实战&#xff09; 概述 如果去欧洲国家去旅游的话&#xff0c;他们的插座如下图最左边&#xff0c;是欧洲标准。而我们使用的插头如下图…

Kindle 可旋转桌面时钟

前言 自己的 Kindle 吃灰很久了&#xff0c;想做个时钟用&#xff0c;但是网上可选的时钟网站比较少&#xff0c;这些时钟网站里面&#xff0c;要么太简单 界面也比较丑陋&#xff0c;要么内容太多 有些本末倒置了&#xff0c;要么网址特别长 输入网址的时候太麻烦。 干脆自己…

【ROS】—— 机器人导航(仿真)—导航原理(十七)

文章目录前言1. 导航模块简介1.1 全局地图1.2 自身定位1.3 路径规划1.4 运动控制1.5 环境感知2. 导航之坐标系前言 &#x1f4e2;本系列将依托赵虚左老师的ROS课程&#xff0c;写下自己的一些心得与笔记。 &#x1f4e2;课程链接:https://www.bilibili.com/video/BV1Ci4y1L7ZZ …

Min_25筛详解

概述 Min_25是日本一个ACM选手的ID&#xff0c;这个筛法是他发明的&#xff0c;所以称之为Min_25筛。它能在亚线性复杂度求出一类积性函数的 fff 的前缀和&#xff0c;前提 是这个积性函数在质数和质数的幂位置的函数值比较好求。借助埃拉托色尼筛的思想 将原问题转化成与质因…

Allegro如何导出和导入设计规则操作指导

Allegro如何导出和导入设计规则操作指导 当需要借用另外一款PCB的设计规则时候,Allegro支持把PCB设计规则导入到另外一块PCB中,如下图 具体操作如下 打开规则管理器打开后如下图

2023.1.15 学习周报

文章目录摘要文献阅读1.题目2.摘要3.介绍4.本文贡献5.PROPOSED METHOD5.1 Problem Formulation5.2 Personalized Time Intervals5.3 Embedding Layer5.4 Time Interval-Aware Self-Attention5.4.1 Time Interval-Aware Self-attention Layer5.4.2 Causality5.4.3 Point-Wise Fe…

QT可直接安装的离线版最后版本5.14.2

以前用c#来做组态&#xff0c;自定义控件开发起来也还过得去&#xff0c;但QT的控件和graphics view貌似更有优势&#xff0c;个人观点吧&#xff01;工控领域的组态用上QT还是不错的选择。 从2000前开始使用qt&#xff0c;算起来也有20多年了。个人感觉用起来最顺手的应该时Q…

【PHP】一文详解如何连接Mysql数据库(附源码)

&#x1f482;作者简介&#xff1a; THUNDER王&#xff0c;一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学会计学专业大二本科在读&#xff0c;同时任汉硕云&#xff08;广东&#xff09;科技有限公司ABAP开发顾问。在学习工作中&#xff0c;我通常使用偏后…

24考研——专业院校选报指南(3步决定专业选择、11大类本科对应考研专业简析、6步决定目标院校)

文章目录一、专业选择指导1.1 考研整体形势1.2 考研专业选报1.2.1 专业设置1.2.2 专硕专业设置1.2.3 专业代码含义1.2.4 区分“学硕和专硕”1.2.5 专业选择步骤&#xff08;跨专业考研难度&#xff09;1.2.6 跨专业考研简析&#xff08;法硕/教育/会计、审计、图书情报/思想政治…

汇编【王爽】实验3、4

实验3 编程、编译、链接、跟踪 assignment 1 编译链接生成可执行文件 assignment 2 debug将程序载入内存&#xff0c;设置CS:IP&#xff1a;程序所在内存段的段地址为DS075CDS075CDS075C&#xff0c;则PSP的地址为075C:0075C:0075C:0&#xff0c;程序的地址为076C:0(075C1…

C++ 初了解模板

一. 泛型编程 我们若是想实现一个需要对各类数据通用的功能&#xff0c;在C语言中是不太现实的&#xff0c;而在C中&#xff0c;我们可以运用函数重载&#xff0c;但我们依然需要写出多个内容极其类似的函数&#xff0c;例如想要实现交换 void Swap(int& a, int& b…

2022这特殊的一年,再见!

望着窗外的夕阳以及还未完全融化的积雪&#xff0c;我想是时候给这特殊的一年写篇总结了。于是我翻看了2021年的&#xff0c;发现文末所定的2022年目标。终于明白为什么老人不玩手机可以坐一下午了&#xff0c;因为往事回想起来就和电视连续剧一样。年初参加了开运跑&#xff0…

【UE】pak的mount(带源码解析)

本文使用的引擎版本为UE4.27 为了方便理解&#xff0c;文中选取的代码均为部分截取&#xff0c;只截取与小节相关的部分 文章目录概述几个涉及到的结构Mount时机pak读取优先级目录优先级根据文件名定优先级综上所述概述 正常的散文件加载是使用FFileHelper::LoadFileToArray等…

【阶段四】Python深度学习06篇:深度学习项目实战:卷积神经网络进行狗狗图像分类项目

本篇的思维导图: 项目背景 应用Keras框架构建卷积神经网络进行狗狗图像分类的预测,以及模型的优化。主要用来熟悉Keras卷积层、池化层网络的使用以及模型的优化方法。 数据获取 本次建模数据来源于网络,数据项统计如下: 数据集为狗狗数据集,来自全国各地的狗狗图…

算法进阶指南:第一章练习题

1.The Pilots Brothers refrigerator 牛客竞赛-The Pilots Brothers refrigerator 116. 飞行员兄弟 - AcWing题库 开关问题的特点是每个开关只会作用某个特定范围&#xff0c;所以每个开关最多操作一次&#xff0c;且操作先后次序对最后结果无影响。用16位二进制存储状态&am…

Unity 过场工具(Cutscene)设计(一)

Unity 过场工具(Cutscene)设计&#xff08;一&#xff09; 游戏中通常会涉及到过场内容的制作&#xff0c;从而来进行一些强表现&#xff0c;从而来进行剧情相关的串联&#xff0c;使游戏表现类容更丰富。比较典型的游戏 像原神&#xff0c;天刀等等游戏。 过场工具制作选择 过…

Java程序设计实验2 | Java语言基础(1)

*本文是博主对Java各种实验的再整理与详解&#xff0c;除了代码部分和解析部分&#xff0c;一些题目还增加了拓展部分&#xff08;⭐&#xff09;。拓展部分不是实验报告中原有的内容&#xff0c;而是博主本人自己的补充&#xff0c;以方便大家额外学习、参考。 目录 一、实验…