前语
一般情况下,咱们要删去一条数据,直接运用 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
。
△图 / 学校博客用户表数据
相同的,也来讲讲这样做的优点:
- 便利数据康复,维护数据自身的价值。
- 保证数据连续性,对主键的影响可能会导致底层B+树重建,而 delete 和 update id 都会影响主键。
事实上,在大多数公司里,都会选用逻辑删去的办法,由于数据的价值更大,被删去的数据也十分有记载价值,这样的操作也并不会进步太多的操作难度。
运用Mybatis-Plus逻辑删去
假如你的项目运用的是Mybatis-Plus结构来操作数据库,那你能够经过下面几个过程快速的转变到逻辑删去形式。
-
在MySQL中给那些要改为逻辑删去的表增加一个
deleted
字段,当然也能够叫flag
或许是其他姓名,只需你喜欢就好。类型tinyint
就够了,默认值最好也设置一下。-- 你也能够直接运用这条修正句子,记得把表名进行替换 ALTER TABLE user ADD `deleted` tinyint UNSIGNED NOT NULL DEFAULT 0 COMMENT '0为未删去,1为已删去';
-
在你的Java代码中给刚刚修正过的表的实体类增加对应的特点:
public class User { // 增加isDeleted字段 Integer isDeleted; }
-
在项目的配置文件(application.yml)傍边增加对应的配置:
mybatis-plus: global-config: db-config: logic-delete-field: isDeleted # 全局逻辑删去的实体字段名 logic-delete-value: 1 # 逻辑已删去值(默以为 1) logic-not-delete-value: 0 # 逻辑未删去值(默以为 0)
-
假如你的Mybatis-Plus版别在 3.3.0 以下,那你还需求在实体类的字段上增加
@TableLogic
注解:@TableLogic Integer isDeleted;
-
假如你的项目中有经过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是这样的:
很显然它并没有帮我加上
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…