当软删除遇到唯一索引
点击↑上方↑蓝色“编了个程”关注我~
这是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层面解决幻读了吗?
当软删除遇到唯一索引相关推荐
- gorm 软删除deleted_at导致索引失效
如果使用gorm的时间戳设计,由于它的deleted_at字段允许为空,唯一索引加上这个字段后,唯一索引会失效. 第一种是像gorm那样,使用时间戳来标识已删除.不同的是,不使用IS NULL来判断未 ...
- MySQL删除全局唯一索引unique
删除索引(通用) alter table 表名 drop index 索引名: drop index 索引名 on 表名 查看索引 show keys from 表名 show index from ...
- 唯一索引和逻辑删除冲突
一. 场景 在数据表结构设计的时候有同时存在唯一索引和逻辑删除,通常逻辑删除is_deleted是取值范围0.1,当删除同一个唯一索引字段值时,就会失败. 二. 解决方案 2.1 物理删除 不再设置逻 ...
- 主键约束、唯一性约束、唯一索引
1.主键约束(PRIMARY KEY) 1) 主键用于唯一地标识表中的每一条记录,可以定义一列或多列为主键. 2) 是不可能(或很难)更新. 3) 主键列上没有任何两行具有相同值(即重复值),不允许空 ...
- ORACLE创建唯一索引
oracle创建唯一索引 Create UNIQUE Index PK_INSTANCE_ID on TB_DD_APPROVAL_OUT (INSTANCE_ID ) oracle基于多列的唯一性约 ...
- mysql删除表中的唯一索引吗_Mysql 使用sql删除同表中重复数据并加唯一索引
同一张表中,假设以两个字段做唯一业务,这两个字段分别为key1,key2, 则以这两个字段为唯一 DELETE tablename FROM tablename , ( SELECT min(id) ...
- 死锁:多线程同时删除唯一索引上的同一行
1 死锁问题背景 1 1.1 一个不可思议的死锁 1 1.1.1 初步分析 3 1.2 如何阅读死锁日志 3 2 死锁原因深入剖析 4 2. ...
- mysql索引 删除和创建_mysql索引和唯一索引的创建和删除
一.本机环境 二.索引的创建删除 三.唯一索引的创建和删除 一.本机环境 系统环境:linux centos 7.2 mysql版本:mysql-5.7.9 安装目录:/application/mys ...
- mysql中怎样查看和删除唯一索引
mysql中怎样查看和删除唯一索引. 查看唯一索引: show index from mytable;//mytable 是表名 查询结果例如以下: 查询到唯一索引后,怎样删除唯一索引呢,使用例如以下 ...
最新文章
- 迭代3:UC1,UC2的2.1 业务建模 2.2 UC2用例模型 2.3 UC2补充性规格说明
- 论文工具 | 翻译神器
- YOLOv5训练coco128数据集流程
- no module named social_django
- 学数据库还不会Select,SQL Select详解,单表查询完全解析?
- STM32使用IIC总线通讯协议在OLED屏幕上显示字符串、汉字、单总线获取DHT11模块温湿度并通过IIC显示到屏幕(软件IIC)
- 实例45:python
- c语言 在歌星大奖赛,C语言 歌星大奖赛为参赛的选手打分
- 使用java IO来读写文件
- python不可实现的领域3d_岩土工程新手入门指南---FLAC3D学习指导与建议
- HTTP协议···(一)
- 数据类型 swift
- postman 第4节 切换环境和设置读取变量(转)
- 西门子S7-200SMART四种密码解密软件
- stm32实验报告心得体会_stm32实验报告心得体会
- vue3.0 ele-plus 与 antd-design的使用
- FMAN(Fully Motion-Aware Network for Video Object Detection)论文详读
- 谢烟客---------Linux之网络基础知识
- Android camera2扫描
- c语言埃尔米特插值思路,【数学建模算法】(26)插值和拟合:埃尔米特(Hermite)插值和样条插值...
热门文章
- JStorm与Storm源码分析(二)--任务分配,assignmen
- 毕设记录-word2vec(skip-gram)实现文本分类
- 数据科学实战系列之ML-KNN(一)
- 汽车喇叭警报器语音芯片应用方案简述,WT588F02B
- 系统架构敏感点,权衡点
- ARC133 B - Dividing Subsequence
- css如何设置全局字体,CSS-如何更改Bootstrap的全局默认字体大小?
- Salesforce的核心密码
- error: the following arguments are required: img, config, checkpoint
- 数据库管理 第一关 用户