聊一聊 MYSQL 数据的真删和假删

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
简介: 聊一聊 MYSQL 数据的真删和假删

前言



简单做个小白文描述。


真删 :


指的就是 彻底地删除, 从数据库表内将数据 进行 移除  delete 。


假删:


指的就是 逻辑上的删除 , 数据库表内, 数据会包含一个标识flag字段 , 例如: status(删除标识,0代表未删除,1代表删除,默认为0) ,执行假删时,只是将数据的 删除标识 status从 0 改 1,update。


正文



真删, 我们就不展开了。


该篇文章其实主要是想聊聊 这个 假删 - 逻辑删除 。


1. 假删的 查询条件问题


既然是对某张表做了假删, 使用  status , 那么在一些业务 查询里面 , 切记切记一定不能忘了,只要使用到 ‘ 假删 ’的数据表, 那么需要带上  status=0 .


2.假删 的验重,数据唯一 问题


验重, 字面意思就是说数据唯一, 而这个数据的唯一保证 ,我们常规地首先是在代码层面做唯一校验,然后在数据库层面也做唯一设置。


为什么说 存在问题?


按照咱们的风格,举个例子来看看:


首先我们现在有一张用于保存企业enterprise信息的表 , 业务上简单理解,需要保证企业唯一,也就是企业名 name唯一(简单举个例子,具体看项目业务需求) 。


enterprise表


image.png保证name的唯一,那么在 企业数据新增时, 按照常规来说我们需要做验重处理。


select  id  from enterprise where name= ' xxxx' ;


看到这里, 可能已经有小伙伴有不一样的看法了, 这个查询的sql是否要带上删除标识?


select  id  from enterprise where name= ' xxxx'  and status = 0 ;


这里也就是指的是, 被执行了假删的数据,是否还需要加入 验重的校验逻辑里?


其实,不同的业务场景,规则肯定不同。 例如上面例子里面介绍的企业信息表, 那么如果企业信息进行假删后, 后面再一次进行企业信息录入时, 企业的名字肯定还是不会变化的。


那么这时候,如果对所谓的 假删数据 stauts=1 还挂钩上,那么就有些不符合常理了,


也就是说,这里的假删不能影响业务,在业务上其实就是已经真正删除掉了。


所以我们需要带上 status= 0 ,保证现在 表内 有效的 企业信息数据中, 不能包含重复数据!


select  id  from enterprise where name= ' xxxx'  and status = 0 ;


ok,这么一看,假删的验重问题似乎已经考虑齐全了,就这么操作。


但是,目前来说也仅仅是代码层面,调用sql时做的处理。  那往往很多时候, 在数据库表创建的时候也需要对数据唯一字段进行唯一索引的创建。


于是乎我们其实还需要考虑一下以下这个引申出来的问题:


假删 数据表 的 唯一索引的创建 问题


回到刚刚例子中的  enterprise表 :


image.png


上边说了下,我们需要保证企业信息唯一,保证企业名 name 的唯一。


那么,按照常规,name字段的 唯一索引(name_index )不可或缺 ,需要创建。


但是,此时这张表其实在验重的时候,进行的逻辑判断 是需要 带上条件 status的。


那么问题就出现了, 对于数据表的真正唯一来说,


其实是 name + status  这两个字段同时保证唯一时, 数据才算是唯一。


也就是说 唯一索引需要升级为唯一组合索引  name字段 & status字段  (name_status_index) .


到这里, 好像是这么一个意思。


这样的唯一组合索引, 跟代码层面的校验规则似乎保持了一致的验重逻辑处理。


保证了吗? 能这样创建吗?


然而并不然!


 image.png


是的, 这个问题的介绍描述 转折确实有点多了。 不过我就是想这么地表达出 一个 针对一个问题的处理、设计解决方案, 需要一步步每个环节都进行把控。


回到正文,为什么说这样 还不行??  唯一组合索引 还不行?


直接看 enterprise表 的模拟数据 :


image.png


可以看到 test公司 这条数据的status是 1 , 那么也就是进行了 所谓的假删 ,逻辑删除。


那么再次创建时, 我们允许创建, 因为在有效数据内 (status=0) ,数据唯一即可,所以表内数据出现:


image.png


这么一看,id为3 的数据 在表内 存在合情合理, 跟id为2 的 被假删数据 ,隔离得很好,没有什么问题。


但是, 再想想,这时候,管理员又把id为 3的数据 进行了 假删。


会出现什么情况?


没错如果我们做了 唯一组合索引 ,那么 再次进行逻辑删除时, 问题出现,  唯一组合索引 不允许 再次 存入   name 为 test公司、status 为 1 的数据,因为之前存在过了。


那这时候,死局了。  


破局思考&方案:


想法一:        


不设置索引了。 仅仅在代码层面做 stauts=0 的有效数据 验重算了。


带来的不好影响:


数据库层面不做唯一拦截,那就会允许存在有误数据。


想法二:  


引入一个新的字段 delete_uuid , 这个字段 作为 唯一组合索引 的成员  ,name_deleteuuid_index.


那么表结构将会变成:


image.png


怎么使用呢, 可以看到 现在的组合唯一索引是 name & delete_uuid ,。


新增数据验重时, 查询加上条件 status =0 and delete_uuid !=NULL   保证有效数据内的唯一性。


然后是针对删除操作, 进行逻辑假删时, 把status改为1 ,并 设置 delete_uuid 为NULL。


(估计有些看官,看到这里会有疑惑, 如果数据 name为test公司 ,删除创建再删除,那么产生了两条 name一样且 delete_uuid 也都是NULL 的数据,数据库允许么? 这就需要给有疑惑的看官科普一下NULL 这个东西的知识了,可以看下下面这篇:


Mysql 唯一索引的字段值 允许多个NULL值存在吗 ?   Mysql 唯一索引的字段值 允许多个NULL值存在吗_默默不代表沉默-CSDN博客)


回归话题内容,


这么一来,即使出现id 为3 和id为2 这种数据场景,需要进行删除时,也不会因为组合索引的唯一性无法进行删除。


带来的不好影响:


复杂度提高了;


多了一个字段,那么一些查询、删除时,就需要考虑到这个字段的使用;


想法三:


逻辑删除的实现上做改变。  本来常规的是 把status从 0 改为 1 ;


那么改为 从 原表 把执行逻辑删除的数据, 迁移插入到历史表 ,


这样原表可以一直保证 name 字段 唯一索引的校验即可。  


带来的不好影响:


既然出现了历史表用于单独存储 假删除的数据, 那么意味着 存储 同个业务数据表其实 一共有两张表 。


我们再回到逻辑删除这个东西的出现, 既然要进行逻辑删除,那么意思就是说,这个数据在一定的情况下,是不允许直接删除,会存在 '恢复' 的情况。


就好比如微信的聊天记录, 删除了,但是微信还是提供了一定条件下做聊天记录的恢复。


那么也就是说,如果有这种恢复的场景 就需要 考虑到两张表的使用操作了。


额外,如果就比如本文中 企业表, 假如 进行逻辑删除的数据需要加入一些数据统计分析业务, 那么 两张表的数据都需要使用到,随之很多业务的实现也会因此而变得不那么直接。


好吧,啰里啰唆地也说了这么多,那就先聊到这了。 大家有什么想法,可以直接评论,都聊一聊假删 这个话题。

相关实践学习
如何在云端创建MySQL数据库
开始实验后,系统会自动创建一台自建MySQL的 源数据库 ECS 实例和一台 目标数据库 RDS。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
1月前
|
关系型数据库 MySQL Java
【MySQL+java+jpa】MySQL数据返回项目的感悟
【MySQL+java+jpa】MySQL数据返回项目的感悟
40 1
|
1月前
|
SQL 监控 关系型数据库
MySQL怎么全局把一张表的数据回滚
MySQL怎么全局把一张表的数据回滚
85 2
|
1月前
|
存储 SQL 关系型数据库
MySQL批量添加数据并取外表的某个字段值
MySQL批量添加数据并取外表的某个字段值
58 1
|
16天前
|
安全 关系型数据库 MySQL
如何将数据从MySQL同步到其他系统
【10月更文挑战第17天】如何将数据从MySQL同步到其他系统
94 0
|
22天前
|
SQL 前端开发 关系型数据库
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
39 0
全表数据核对 ,行数据核对,列数据核对,Mysql 8.0 实例(sample database classicmodels _No.3 )
|
27天前
|
关系型数据库 MySQL 数据库
mysql 里创建表并插入数据
【10月更文挑战第5天】
106 1
|
29天前
|
分布式计算 关系型数据库 MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
大数据-88 Spark 集群 案例学习 Spark Scala 案例 SuperWordCount 计算结果数据写入MySQL
46 3
|
1天前
|
SQL 前端开发 关系型数据库
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
SpringBoot使用mysql查询昨天、今天、过去一周、过去半年、过去一年数据
23 9
|
12天前
|
SQL Java 关系型数据库
java连接mysql查询数据(基础版,无框架)
【10月更文挑战第12天】该示例展示了如何使用Java通过JDBC连接MySQL数据库并查询数据。首先在项目中引入`mysql-connector-java`依赖,然后通过`JdbcUtil`类中的`main`方法实现数据库连接、执行SQL查询及结果处理,最后关闭相关资源。
|
9天前
|
SQL 关系型数据库 MySQL
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
定时任务频繁插入数据导致锁表问题 -> 查询mysql进程
23 1