【MySQL】解决软删除中的唯一索引问题

1. 起因

最近在学习go-zero,用go-zero自带的sqlx+sqlc操作数据库。因为sqlx+sqlc不会像gorm一样自动管理软删除字段,所以对表结构进行重新的设计。 下面是新的表结构:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
DROP TABLE IF EXISTS `user`;
CREATE TABLE `user` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT '用户id',
`username` varchar(50) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '用户名',
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_0900_ai_ci NOT NULL COMMENT '密码',
`create_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`delete_time` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '删除时间',
`is_delete` tinyint unsigned NOT NULL DEFAULT '0' COMMENT '是否被删除',
`version` bigint unsigned NOT NULL DEFAULT '0' COMMENT '版本号',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_username` (`username`,`is_delete`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci COMMENT='用户记录';

业务上需要username上这个唯一索引,同时当业务需要删除数据时只能软删除,方便数据溯源与恢复。

2. 遇到的问题

当时只考虑到业务语义上username需要唯一索引,写完代码后用 postman 进行测试,插入一条数据,再删除这条数据。再插入一条相同用户名的数据时, 接口报错唯一索引冲突。参考go-zero微信群的建议,给软删除字段is_delete也加上唯一索引。插入一条数据,再删除这条数据。再插入一条相同用户名的数据, 再删除这条数据时,接口还是报错唯一索引冲突。

3. 再加索引

群里立马又有大佬说还需要给删除时间加上唯一索引,因为删除时业务上会把删除时间更新为当前时间,不会有冲突。一顿操作下来,就给三个字段加上了唯一索引。 个人感觉这个索引还是有点大,又去网上找了不少相关博客。首先确定的是:

  • 有唯一索引需要的字段必须加上唯一索引,不能因为业务上有校验就删除该索引。
  • 同时删除数据时应该使用软删除。
  • 但是有一点可以优化,就是标记软删除的字段不必只是 0 和 1,当删除数据时,更新该字段为该记录的主键值

4. 又遇到问题

因为go-zero的数据库操作代码是靠代码生成的,会根据索引字段自动生成方法名,当有唯一索引需求是,自动生成的方法名会带上索引的所有字段,包括 软删除字段,方法名格外尴尬不说,内部生成的代码还多判断了一次is_delete = 0,请教了 looklook 项目作者,这种需要 fork go-zero源代码再自己进行魔改。

Licensed under CC BY-NC-SA 4.0
comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计