前语

一般情况下,咱们要删去一条数据,直接运用 delete 即可,就像这样:delete from user where id = 1,这样做的优点是:

  • 符合咱们的理解,删去便是直接删掉嘛。
  • 节省数据库空间,某些情况下数据量较大,且新增和删去比较频频时,delete能够帮咱们收回很多的空间。

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

逻辑删去

逻辑删去便是给数据表增加一个固定字段,用该字段的值来表明这条数据当时是否被删去,并把 delete 操作修正为 update 操作。

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

当我要删去某条数据时,我会将这条数据的 deleted 值置为 1,而不会运用 delete 去真实的把它删掉。一起,我的一切 insert 句子和 update 句子都会带上一个固定的条件 deleted = 0 ,来过滤掉一切在逻辑上被删去的数据。

阿里巴巴Java编码规约提出:POJO 类中布尔类型的变量,都不要加 is,不然部分结构解析会引起序列化过错。

我原来是用的 is_deleted,现已悉数更改为了 deleted

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

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

相同的,也来讲讲这样做的优点:

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

事实上,在大多数公司里,都会选用逻辑删去的办法,由于数据的价值更大,被删去的数据也十分有记载价值,这样的操作也并不会进步太多的操作难度。

运用Mybatis-Plus逻辑删去

假如你的项目运用的是Mybatis-Plus结构来操作数据库,那你能够经过下面几个过程快速的转变到逻辑删去形式。

  1. 在MySQL中给那些要改为逻辑删去的表增加一个 deleted 字段,当然也能够叫 flag 或许是其他姓名,只需你喜欢就好。类型 tinyint 就够了,默认值最好也设置一下。

    -- 你也能够直接运用这条修正句子,记得把表名进行替换
    ALTER TABLE user ADD `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 句子都加一个过滤条件 deleted = 0
    • insert 句子,假如你在表上设置了默认值的话,则能够不用管它。假如你没有设置默认值,那我建议你还是设置一下。

好了就这么简略,你乃至不需求修正你的业务代码,由于Mybatis-Plus已经帮你处理好了。

它做了什么

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

    update user set deleted = 1 where id = 1 and deleted = 0
    
  • 当你经过QueryWrapper查询数据或许经过 UpdateWrapper 更新数据的时分,它也会自动帮你增加过滤条件:

    select * from user where deleted = 0
    
  • 但假如你是在xml中直接写的SQL句子,那它是不会帮你进行修正的,比方我写的SQL是这样的:

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

    执行出来的SQL是这样的:

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

    很显然它并没有帮我加上 deleted = 0 ,这是运用者需求留意的。

当然我只是简略的对Mybatis-Plus的逻辑删去功能用法进行了简略解说,假如你需求的话,也能够参阅一下官方文档的阐明:逻辑删去 | MyBatis-Plus (baomidou.com) (尽管它写的也比较简洁‍)

留意

尽管把项目过渡到逻辑删去并不太费事,但它也有一些其他需求留意的点。

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

  • 逻辑删去是为了便利数据康复和维护数据自身价值等等的一种方案,但实践便是删去。
  • 假如你需求频频查出来看就不该运用逻辑删去,而是以一个状况去表明。

其次是运用逻辑上,关于MySQL而言,逻辑删去会导致仅有索引(UNIQUE KEY)的反常。

  • 原因很简略,已经删去的数据依然存在,当再次刺进一条相同的数据时,就会抛出反常。

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

    那么理论上来说此时是应该允许刺进的,但由于我运用了逻辑删去,MySQL不允许存在两条数据呈现相同的 username = 阿杆的场景,此时就呈现了反常。

  • 当然,逻辑删去与仅有索引的冲突是能够处理的,处理方案也不难。

    咱们能够在原来的仅有索引里加上deleted字段,一起再删去数据的时分把deleted修正为表id,这样就能够保证未删去的数据不会呈现重复值了,并且不会受到已删去数据的影响。但你要记得重写SQL办法,不然Mybatis-Plus还是会帮你修正为配置文件里的那个默认值。

    UNIQUE KEY `username` (`username`,`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,项目地址:github.com/stick-i/scb…

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