点击↑上方↑蓝色“编了个程”关注我~

这是Yasin的第 53 篇原创文章

Y说

最近几周工作上都有点忙,有点精力不够消耗的感觉。

周末倒是没有太多事情,但只想睡觉。

杭州这两天天气都挺好的,阳光不错,每天都会在饭后去隔壁小区的花园里走一走,晒晒太阳。

感觉日子很平静,又过得很快,尤其是周末,感觉什么都没做,但很快就又到周一了。

于是在周日晚上抓住这个周末的尾巴,写一篇文章出来。这个问题是我前段时间在工作中用到的,相信很多开发者也会遇到这个问题,所以分享出来。

什么是软删除

计算机的世界要比真实世界严谨得多。

我们一般不会把数据真正删除,哪怕是在用户来看,这条数据已经是删除了的。比如你发了一条动态,觉得不合适,在自己的APP上把它删除掉,自己和别人都看不到了。

但在数据库中,这条数据一旦创建后就会一直存在,在用户点“删除”按钮的时候,只是给它设置了一个标识,代表它“已删除”,后续通过应用的正常查询,是会过滤掉这条数据的。

但在我们开发人员排查问题或者做数据分析的时候,这条数据是可见的。

要实现软删除成本不大,也不会浪费很多磁盘空间,但带来的好处是可见的,一方面是方便排查问题,可以知道这条数据情况;另一方面是程序出现了问题,导致数据出现错误时,还有补救的机会。

如何实现软删除

实现软删除有几种方案。

最常见的就是设置一个字段,用来标识这条数据是否被删除。常见的数据类型有布尔类型(在MySQL中一般用tinyint来实现);字符串类型(一般是y/n或者yes/no)。我之前在阿里所在的团队就是使用的字符串y/n的设计。

gorm是一个golang的orm框架,它的设计是一个类型为时间的字段,叫deleted_at。如果为空,代表未删除,如果不为空,代表已删除,其值就是删除的时间。

一般场景下,这两种设计都没有任何问题。但如果遇到了唯一索引,那这两种设计都会出现问题。

软删除遇到唯一索引

唯一索引指的是在数据库层面来约束数据的唯一性。比如:每个人的身份证号是独一无二的,不可重复的。那就可以通过给身份证号添加唯一索引来约束。

但如果我们的表用上述两种方式实现了软删除的功能,那使用唯一索引就会出现问题。

首先,「对于使用了软删除的表,唯一索引上必须要加上软删除的字段」,否则已经被删除的数据可能会和新插入的正常数据引起冲突。比如:如果一个博客系统,标题+作者是唯一的。一个用户发了一篇文章,但对内容不满意,删除了。后来又重新发了一篇标题一样的文章,这个时候如果唯一索引没加软删除字段的话,就会报唯一索引冲突。

如果我们使用布尔值或字符串来实现软删除功能,那被删除两次的相同数据会引起唯一键冲突。比如同样是这个博客系统,我删除了一篇文章,又写了一篇标题一样的文章,结果这篇文章也想删除的时候,就会报唯一索引冲突,删除失败。

如果使用gorm的时间戳设计,由于它的deleted_at字段允许为空,唯一索引加上这个字段后,唯一索引会失效。这个时候同一个用户是可以创建两篇标题一模一样的文章的,违背了产品的设计。

其它设计

那如何解决这个问题呢?

其实顺着这个思路去想,是很好解决这个问题的。

首先,软删除字段不能为空,否则唯一索引就失效了。

其次,已删除的数据要想办法不被唯一索引检测到冲突,但未删除的数据又需要被唯一索引检测到冲突。那代表这个唯一索引不能是简单的布尔值,且需要一个“默认值”。

那就可以想到两种设计了。

第一种是像gorm那样,使用时间戳来标识已删除。不同的是,不使用IS NULL来判断未删除的数据,而使用=0来判断未删除的数据。也就是说,deleted_at是非空的,默认值是0。事实上我今天在翻gorm官方文档的时候,发现它其实也是支持这种设计的:

import "gorm.io/plugin/soft_delete"type User struct {ID        uintName      stringDeletedAt soft_delete.DeletedAt
}// Query
SELECT * FROM users WHERE deleted_at = 0;// Delete
UPDATE users SET deleted_at = /* current unix second */ WHERE ID = 1;

另一种就是使用deleted_id来作为软删除字段。默认值是0(如果主键是字符串类型,默认为空字符串),如果是已删除的数据,那更新deleted_id=id

总结

目前项目上都是深度使用的gorm。之前觉得它的软删除设计有些奇怪,但没有细想到底奇怪在哪里,就正常使用了一段时间,直到前段时间发现唯一索引是不生效的,才觉察到有问题。

之前在阿里那种y/n设计是明确有问题的,但当时也没深究怎么去解决。而且软删除这种功能很多时候都是写死在了orm框架里,有时候是没法改变的。

后续翻资料和文档,与同事讨论,发现也有其它不错的解决方案,看来以后在工作中还是要多问自己几个为什么,多思考和查阅资料,才能把软件设计得更好一点。

关于作者

我是Yasin,一个爱写博客的技术人

微信公众号:编了个程(blgcheng)

个人网站:https://yasinshaw.com

欢迎关注这个公众号

数据源切换的一般步骤

MySQL到底在RR层面解决幻读了吗?

当软删除遇到唯一索引相关推荐

  1. gorm 软删除deleted_at导致索引失效

    如果使用gorm的时间戳设计,由于它的deleted_at字段允许为空,唯一索引加上这个字段后,唯一索引会失效. 第一种是像gorm那样,使用时间戳来标识已删除.不同的是,不使用IS NULL来判断未 ...

  2. MySQL删除全局唯一索引unique

    删除索引(通用) alter table 表名 drop index 索引名: drop index 索引名 on 表名 查看索引 show keys from 表名 show index from ...

  3. 唯一索引和逻辑删除冲突

    一. 场景 在数据表结构设计的时候有同时存在唯一索引和逻辑删除,通常逻辑删除is_deleted是取值范围0.1,当删除同一个唯一索引字段值时,就会失败. 二. 解决方案 2.1 物理删除 不再设置逻 ...

  4. 主键约束、唯一性约束、唯一索引

    1.主键约束(PRIMARY KEY) 1) 主键用于唯一地标识表中的每一条记录,可以定义一列或多列为主键. 2) 是不可能(或很难)更新. 3) 主键列上没有任何两行具有相同值(即重复值),不允许空 ...

  5. ORACLE创建唯一索引

    oracle创建唯一索引 Create UNIQUE Index PK_INSTANCE_ID on TB_DD_APPROVAL_OUT (INSTANCE_ID ) oracle基于多列的唯一性约 ...

  6. mysql删除表中的唯一索引吗_Mysql 使用sql删除同表中重复数据并加唯一索引

    同一张表中,假设以两个字段做唯一业务,这两个字段分别为key1,key2, 则以这两个字段为唯一 DELETE tablename FROM tablename , ( SELECT min(id) ...

  7. 死锁:多线程同时删除唯一索引上的同一行

    1    死锁问题背景    1 1.1    一个不可思议的死锁    1 1.1.1    初步分析    3 1.2    如何阅读死锁日志    3 2    死锁原因深入剖析    4 2. ...

  8. mysql索引 删除和创建_mysql索引和唯一索引的创建和删除

    一.本机环境 二.索引的创建删除 三.唯一索引的创建和删除 一.本机环境 系统环境:linux centos 7.2 mysql版本:mysql-5.7.9 安装目录:/application/mys ...

  9. mysql中怎样查看和删除唯一索引

    mysql中怎样查看和删除唯一索引. 查看唯一索引: show index from mytable;//mytable 是表名 查询结果例如以下: 查询到唯一索引后,怎样删除唯一索引呢,使用例如以下 ...

最新文章

  1. 迭代3:UC1,UC2的2.1 业务建模 2.2 UC2用例模型 2.3 UC2补充性规格说明
  2. 论文工具 | 翻译神器
  3. YOLOv5训练coco128数据集流程
  4. no module named social_django
  5. 学数据库还不会Select,SQL Select详解,单表查询完全解析?
  6. STM32使用IIC总线通讯协议在OLED屏幕上显示字符串、汉字、单总线获取DHT11模块温湿度并通过IIC显示到屏幕(软件IIC)
  7. 实例45:python
  8. c语言 在歌星大奖赛,C语言 歌星大奖赛为参赛的选手打分
  9. 使用java IO来读写文件
  10. python不可实现的领域3d_岩土工程新手入门指南---FLAC3D学习指导与建议
  11. HTTP协议···(一)
  12. 数据类型 swift
  13. postman 第4节 切换环境和设置读取变量(转)
  14. 西门子S7-200SMART四种密码解密软件
  15. stm32实验报告心得体会_stm32实验报告心得体会
  16. vue3.0 ele-plus 与 antd-design的使用
  17. FMAN(Fully Motion-Aware Network for Video Object Detection)论文详读
  18. 谢烟客---------Linux之网络基础知识
  19. Android camera2扫描
  20. c语言埃尔米特插值思路,【数学建模算法】(26)插值和拟合:埃尔米特(Hermite)插值和样条插值...

热门文章

  1. JStorm与Storm源码分析(二)--任务分配,assignmen
  2. 毕设记录-word2vec(skip-gram)实现文本分类
  3. 数据科学实战系列之ML-KNN(一)
  4. 汽车喇叭警报器语音芯片应用方案简述,WT588F02B
  5. 系统架构敏感点,权衡点
  6. ARC133 B - Dividing Subsequence
  7. css如何设置全局字体,CSS-如何更改Bootstrap的全局默认字体大小?
  8. Salesforce的核心密码
  9. error: the following arguments are required: img, config, checkpoint
  10. 数据库管理 第一关 用户