如何建立含有逻辑删除字段的唯一索引
业务场景
在实际工作当中,遇到一个场景,就是在用户注册时,名字要全局唯一,当然,我们是可以对用户进行删除的,你会怎么去做?
分析
一般来说,我们可以在用户注册请求时,进行查库校验,看看名字是否已经存在,如果存在就抛异常给提示;否则,就落库。
除此之外,还可以直接给数据库字段加唯一索引
UNIQUE KEY `name_index` (`name`) USING BTREE
当前这种需要根据实际情况分析:
- 如果我们删除用户是物理删除,就是直接delete,没问题
- 如果我们删除用户是逻辑删除,相对于update数据的删除标识为1,这时候你怎么建唯一索引?
针对第二种情况,可能很多人会说,把删除标识字段也加到索引里面,类似
NIQUE KEY `name_index` (`name`,`is_deleted`) USING BTREE
这里会有问题,当我们进行相同用户第二次删除之后,把id=3的数据删除(逻辑),修改is_deleted=1,此时就会报错,如下图
+----+---------+-----------+
| id | name | is_deleted |
+----+---------+-----------+
| 1 | forlan0 | 0 |
| 2 | forlan1 | 1 |
| 3 | forlan1 | 0 |
+----+---------+-----------+

那么,针对逻辑删除这种情况,怎么处理?
解决
1、删除时,修改is_deleted=主键
UPDATE forlan SET `is_deleted` = id WHERE `id` = 3;
--修改后的数据如下
+----+---------+------------+
| id | name | is_deleted |
+----+---------+------------+
| 1 | forlan0 | 0 |
| 2 | forlan1 | 2 |
| 3 | forlan1 | 3 |
+----+---------+------------+
2、删除时,修改is_deleted=null
这种做法,不是会有两条相同的数据?下面的情况允许存在?
UPDATE forlan SET `is_deleted` = NULL WHERE `id` = 3;
--修改后的数据如下
+----+---------+------------+
| id | name | is_deleted |
+----+---------+------------+
| 1 | forlan0 | 0 |
| 2 | forlan1 | NULL |
| 3 | forlan1 | NULL |
+----+---------+------------+
Mysql官方文档的解释
A UNIQUE index creates a constraint such that all values in the index must be distinct. An error occurs if you try to add a new row with a key value that matches an existing row. This constraint does not apply to NULL values except for the BDB storage engine. For other engines, a UNIQUE index allows multiple NULL values for columns that can contain NULL.
其实大概意思就是,除BDB存储引擎外,此约束不适用于NULL值。对于其他引擎,UNIQUE索引允许包含NULL的列有多个NULL值
为什么允许这么搞?
我的理解是,NULL其实就表示未知,未知的东西,无法进行判断;如果NULL对唯一索引起作用,那么就会导致只能有1行数据为空,我们的业务场景,可能需要用NULL去表示未知或不确定的值。
当前,还是不太建议使用NULL,可能存在一些其它问题,比如:
- 数据丢失
阿里巴巴规范里面也说了,count(*) 会统计值为 NULL 的行,而 count(列名) 不会统计此列为 NULL 值的行
WHERE条件!=不会查到NULL的值 - 程序空指针报错,比如我们使用SUM(cloumn),如果字段都为NULL,最终返回NULL
- 增加查询难度
查询时,语法需要使用IS NULL 、IS NOT NULL、IFNULL(cloumn) 而传统的 =、!=等就不能使用了
3、新建一个字段delete_id,删除时,修改delete_id=主键
正常来说,其实1,2种方案已经满足,为什么我们要使用这种?
假设我们的表已经上线使用了一段时间,这时我们需要建唯一索引,就可以采取方案,实际上就是在删除的时候,多更新一个字段
UPDATE forlan SET `is_deleted` = 1,delete_id = id WHERE `id` = 3;
总结
有3种数据库层面的解决方案:
- 删除时,修改is_deleted=主键
- 删除时,修改is_deleted=null
- 新建一个字段delete_id,删除时,修改delete_id=主键
至于怎么选择,看业务场景:
如果是已经投入使用的业务,可以采取方案3,否则可以采取方案1。
相关文章:
如何建立含有逻辑删除字段的唯一索引
业务场景 在实际工作当中,遇到一个场景,就是在用户注册时,名字要全局唯一,当然,我们是可以对用户进行删除的,你会怎么去做? 分析 一般来说,我们可以在用户注册请求时,…...
C语言基础知识点一
C语言基础知识点一: 1.数据类型 2.bool类型: 使用bool时时,需要增加<stdbool.h>头文件。 说明:bool 类型只有非零(true)和零(false)两种值。 如: if(-1…...
Python 潮流周刊#14:Lpython 高性能编译器、Python 与 JavaScript 实现互通
△点击上方“Python猫”关注 ,回复“1”领取电子书 你好,我是猫哥。这里每周分享优质的 Python、AI 及通用技术内容,本期分享的全部是英文材料。(标题取自其中两则分享,不代表全部内容都是该主题,特此声明。…...
JVM深入 —— JVM的体系架构
前言 能否真正理解JVM的底层实现原理是进阶Java技术的必由之路,Java通过JVM虚拟机的设计使得Java的延拓性更好,平台无关性是其同时兼顾移动端和服务器端开发的重要特性。在本篇文章中,荔枝将会仔细梳理JVM的体系架构和理论知识,希…...
dialog => :before-close的属性应用
在element-ui里面关闭弹窗的时候before-close会触发。 也就是点击X的时候回触发before-close这个属性, 代码实例: <el-dialogtitle"新增用户":visible.sync"dialogVisible"width"50%":before-close"handleClose"> handleClose…...
<van-empty description=““ /> 滚动条bug
使用 <van-empty description"" /> 时,图片出现了个滚动条,图片可以上下滑动。 代码如下: <block wx:if"{{courseList.length < 0}}"><van-empty description"" /> </block> <…...
使用swiper实现图片轮播功能
swiper中文官网地址:在这里 官网介绍:Swiper是纯javascript打造的滑动特效插件,面向手机、平板电脑等移动终端。 按照使用方法下载指定版本的swiper文件; 需要用到的文件有swiper-bundle.js和swiper-bundle.css文件,还需要引入map文件,不然会有警告提示; 准备工作:…...
Qt应用开发(基础篇)——时间类 QDateTime、QDate、QTime
一、前言 时间类QDateTime、QDate、QTime、QTimeZone保存了Qt的时间、日期、时区信息,常用的时间类部件都会用到这些数据结构,常用概念有年、月、日、时、分、秒、毫秒和时区,时间和时区就关系到时间戳和UTC的概念。 UTC时间,又称…...
Modbus TCP转Profinet网关modbus tcp转以太网
大家好,今天我们来聊一聊如何使用捷米特的Profinet转modbusTCP协议转换网关在博图上进行非透传型配置。 1, 首先,我们需要安装捷米特JM-TCP-PN的GSD文件,并根据现场设备情况配置modbusTCP地址。然后,在博图中添加该GSD文件&#x…...
笔记 | P4387 【深基15.习9】验证栈序列 题解
题解 问题描述 给出两个序列 pushed 和 poped,分别表示入栈和出栈操作的顺序。我们需要判断给定的出栈序列是否可能对应于给定的入栈序列。如果可能,则输出 “Yes”;否则,输出 “No”。 解题思路 读取输入:读取询问…...
PyTorch中nn-XXX与F-XXX的区别
nn.XXX与F.XXX PyTorch中torch.nn**(以下简写为nn)中的模块和torch.nn.functional(以下简写为F)**中的模块都提供了常用的神经网络操作,包括激活函数、损失函数、池化操作等。它们的主要区别如下: nn中的…...
zookeeper集群和kafka的相关概念就部署
目录 一、Zookeeper概述 1、Zookeeper 定义 2、Zookeeper 工作机制 3、Zookeeper 特点 4、Zookeeper 数据结构 5、Zookeeper 应用场景 (1)统一命名服务 (2)统一配置管理 (3)统一集群管理 (4&a…...
第4集丨Vue 江湖 —— 计算属性
目录 一、基本使用1.1 在computed中定义1.1.1 案例1.1.2 控制台调用getter1.1.3 控制台中的data和computed 1.2 缓存效果1.3 完整写法1.3.1 案例1.3.2 效果图 1.4 简写形式 二、案例的其他实现2.1 methods实现2.2 插值语法实现 三、体会计算属性的好处3.1 复杂任务时3.2 使用计…...
Docker 容器化学习
文章目录 前言Docker架构 1、 docker安装2、启动docker服务3、设置docker随机器一起启动4、docker体验5、docker常规命令5.1、容器操作docker [run|start|stop|restart|kill|rm|pause|unpause]docker [ps|inspect|exec|logs|export|import] 5.2、镜像操作docker images|rmi|tag…...
springboot第34集:ES 搜索,nginx
#用search after解决深分页性能问题 #第一页 GET /bank/_search {"size": 10,"sort": [{"account_number": {"order": "asc"}}] }#第二页 GET /bank/_search {"size": 10,"sort": [{"account_numb…...
微信小程序中的分包使用介绍
一、分包的好处 可以优化小程序首次启动的下载时间 在多团队共同开发时可以更好的解耦协作 主包:放置默认启动页面/TabBar 页面,公共资源/JS 脚本 分包:根据开发者的配置进行划分 限制:所有分包大小不超过 20M,单…...
【云原生】K8S二进制搭建二:部署CNI网络组件
目录 一、K8S提供三大接口1.1容器运行时接口CRI1.2云原生网络接口CNI1.3云原生存储接口CSI 二、Flannel网络插件2.1K8S中Pod网络通信2.2Overlay Network2.3VXLAN2.4Flannel 三、Flannel udp 模式的工作原理3.1ETCD 之 Flannel 提供说明 四、vxlan 模式4.1Flannel vxlan 模式的工…...
【iOS】—— 离屏渲染
文章目录 离屏渲染UIView和CALayer关系GPU屏幕渲染有两种方式:产生离屏渲染的原因:既然离屏渲染这么耗性能,为什么有这套机制呢?什么情况会离屏渲染?既然离屏渲染这么不好,为什么我们还要强制开启呢?如何避免离屏渲染?…...
基于人工智能的中医图像分类系统设计与实现
华佗AI 《支持中医,永远传承古老文化》 本存储库包含一个针对中药的人工智能图像分类系统。该项目的目标是通过输入图像准确识别和分类各种中草药和成分。 个人授权许可证 版权所有 2023至2050特此授予任何获得华佗AI应用程序(以下简称“软件”)副本的人免费许可,可根据以…...
spring security + oauth2 使用RedisTokenStore 以json格式存储
1.项目架构 2.自己对 TokenStore 的 redis实现 package com.enterprise.auth.config;import org.springframework.data.redis.connection.RedisConnection; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis…...
零基础也能学!收藏这份AI大模型入门指南,开启你的高薪之路
本文介绍了AI大模型在当前科技趋势中的核心地位,以及各行各业对AI人才的迫切需求。文章指出,即使没有技术基础,普通人也能通过学习应用开发路线掌握AI技能,并提供了循序渐进的学习步骤,包括打好Python编程基础、学习提…...
解放你的B站缓存视频:3步让m4s文件变身为通用MP4格式
解放你的B站缓存视频:3步让m4s文件变身为通用MP4格式 【免费下载链接】m4s-converter 一个跨平台小工具,将bilibili缓存的m4s格式音视频文件合并成mp4 项目地址: https://gitcode.com/gh_mirrors/m4/m4s-converter 你是否曾经在B站缓存了精彩的教…...
基于ESP32与EzDIO的离线人脸识别门锁DIY全攻略
1. 项目概述:从智能门锁到人脸识别,一个DIY玩家的实践最近几年,智能家居的概念越来越火,从手机控制灯光到语音助手开关窗帘,似乎万物皆可“智能”。作为一个喜欢折腾硬件的玩家,我总觉得市面上的成品智能门…...
MRI绕组结构设计及均匀度优化算法【附算法】
✨ 长期致力于MRI、均匀度、球面谐波、目标场、主被动匀场、优化算法、超导磁体、线性规划、非线性规划研究工作,擅长数据搜集与处理、建模仿真、程序编写、仿真设计。 ✅ 专业定制毕设、代码 ✅ 如需沟通交流,点击《获取方式》 (1࿰…...
从零构建嵌入式Linux平板:基于全志H3与Qt5的实战指南
1. 项目概述:为什么我们要自己动手做一块“平板”?几年前,我在一个嵌入式展会上看到一块工业平板,功能简单但价格不菲。当时我就在想,它的核心无非就是一块屏幕、一个主控板和一个定制的用户界面。既然我们有开源的Lin…...
Linux入门指南:从内核到终端,掌握核心命令与文件操作
1. 从内核到终端:理解Linux的运作逻辑很多刚接触Linux的朋友,包括我当年,都会觉得它是一堆神秘命令的集合。输入几个字母,敲下回车,系统就乖乖听话了。但要想真正用好Linux,而不是死记硬背命令,…...
别再只用K-Means了!用DBSCAN搞定非球形数据聚类(附Python代码实战)
突破K-Means局限:DBSCAN在复杂数据聚类中的实战指南 当数据科学家面对那些"不听话"的非球形分布数据集时,传统K-Means算法往往会束手无策。想象一下这样的场景:你的客户分群数据呈现出笑脸形状的分布,或者市场调研数据形…...
运算放大器:从虚短虚断到负反馈,掌握模拟电路核心设计
1. 从“石头”与“水库”到“运算放大器”:一个电子世界的演化故事如果你拆开过任何一台现代电子设备,从手机到汽车,从血糖仪到工业机器人,你大概率会找到一个或多个不起眼的八脚或十四脚黑色小方块——运算放大器。它不像CPU那样…...
Creo二次开发避坑:用ProAsmcomppathInit搞定装配体遍历,别再卡在ProFeature转ProAsmcomppath了
Creo二次开发实战:高效构建装配体遍历路径的深度解析 在Creo二次开发领域,装配体遍历是许多高级功能的基础操作,但开发者常常会在ProFeature到ProAsmcomppath的转换过程中遭遇瓶颈。本文将从底层数据结构入手,揭示一种被多数文档忽…...
终极指南:三分钟轻松解锁《原神》60帧限制,让你的高刷显示器火力全开![特殊字符]
终极指南:三分钟轻松解锁《原神》60帧限制,让你的高刷显示器火力全开!🎮 【免费下载链接】genshin-fps-unlock unlocks the 60 fps cap 项目地址: https://gitcode.com/gh_mirrors/ge/genshin-fps-unlock 还在为《原神》60…...
