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
源代码再自己进行魔改。