如何解决逻辑删除与数据库唯一约束冲突

前言

不知道大家有没有遇到这么一种业务场景,在业务中有个唯一约束A,当该业务进行逻辑删除后(设置标记为删除状态),再往唯一约束列插入相同的值时,此时会报Duplicate entry,但在业务上,该值时必须要插入的。今天我们就来聊聊处理这种业务场景的几种思路

解决思路

方案一:不采用逻辑删除,直接物理删除

方案二:新建历史表

主表进行物理删除,同时将删除的记录保存到历史表中

方案三:取消表的唯一约束,同时引入redis来保证唯一约束

取消表的唯一约束,在项目中引入redis,通过redis来判重,新增时往redis set记录,删除时,删除redis记录

方案四:变更删除标记为时间戳

将删除状态不以0,1表示,而是以时间戳为值,然后将删除状态为与之前的唯一约束A重新组成唯一联合约束index(A、del_flag),删除时变更del_flag的时间戳

方案五:保留删除标记,同时新建一个字段del_unique_key

保留删除状态位,再新增一个字段del_unique_key,该字段默认值为0,字段类型和大小与主键id保持一致,同时与原先的唯一约束重新组成联合唯一约束index(A,del_unique_key),业务进行逻辑删除,变更del_unique_key的值为该删除行的主键id

方案的取舍

方案一得从业务的角度上考虑了,如果物理删除,对业务无损,那就无所谓了。方案二等于需要删除的记录的表都需要有历史表,如果仅仅是用来实现记录删除记录,感觉有点大材小用。方案三引入redis,虽然也可以解决问题,但是又额外增加复杂度,同时还得保证redis和数据库的一致性。方案四和方案五其实实现的思路是一样,不过如果已经是在线上跑的业务,还是推荐用第五种方案,毕竟新增字段正常对已有的业务影响相对较小,如果是第四种方案,直接将标志位修改为时间戳,可能还会涉及改业务。如果是新增业务,第四种和第五种方案比较推荐

### MySQL 唯一约束使用方法 唯一约束(UNIQUE Constraint)确保某列或多列组合中的所有值都是唯一的,这样可以防止重复的数据进入表中。这有助于保持数据的完整性和准确性。 定义唯一约束可以在创建表时完成,也可以在之后修改表结构来添加该约束。以下是两种方式的具体实现: #### 创建表时设置唯一约束 当首次建立新表的时候可以直接指定某一列为唯一键。下面是一个例子,在此示例中,`email` 字段被设为了唯一键[^3]。 ```sql CREATE TABLE users ( id INT AUTO_INCREMENT PRIMARY KEY, email VARCHAR(255) UNIQUE NOT NULL, password CHAR(60), created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ); ``` #### 修改现有表以增加唯一约束 如果已经存在一张未设定唯一性的表格,则可以通过 `ALTER TABLE` 来追加这个特性给特定字段。这里展示如何向已有的 `users` 表里加入名为 `unique_email` 的唯一索引。 ```sql ALTER TABLE users ADD CONSTRAINT unique_email UNIQUE (email); ``` 对于多列组成的联合唯一性条件同样适用上述语法;只需把多个字段名放在括号内并用逗号分隔即可。 ### 解决唯一约束有关的问题方案 有时可能会因为违反了唯一约束而收到错误提示。比如尝试插入一条具有相同邮箱地址的新用户记录到上面的例子中就会失败,并抛出类似于 "Duplicate entry 'example@example.com' for key 'users.email'" 的异常信息。针对这种情况有几种处理办法: - **更新而非插入**:检查是否有现存匹配项后再决定执行更新还是继续新增操作。 - **忽略冲突**:利用 ON DUPLICATE KEY UPDATE 子句让 SQL 自动跳过或覆盖已有条目而不报错。例如: ```sql INSERT INTO users (email, password) VALUES ('existing@example.com', '$hashed_password') ON DUPLICATE KEY UPDATE password=VALUES(password); ``` - **捕获异常**:编写应用程序级别的逻辑捕捉此类SQLSTATE异常码(`23000`),进而实施更复杂的业务流程控制措施。 另外值得注意的是,当涉及到逻辑删除功能时,由于某些情况下即使标记为“已删”的旧纪录仍占据着原本属于它们的空间位置,因此如果不小心设计的话就有可能造成新的正常实体无法成功注册其独占属性值的情况发生。为了避免这种潜在矛盾的发生,建议考虑引入额外过滤器排除掉那些处于隐藏状态下的实例参唯一性验证过程[^5]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值