具有软删除,唯一键和外键约束的MySQL

时间:2010-08-16 10:57:08

标签: mysql database-design foreign-keys constraints

假设我有两个表,usercomment。它们的表定义如下所示:

CREATE TABLE `user` (
  `id`       INTEGER NOT NULL AUTO_INCREMENT,
  `username` VARCHAR(255) NOT NULL,
  `deleted`  TINYINT(1) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  UNIQUE KEY (`username`)
) ENGINE=InnoDB;
CREATE TABLE `comment` (
  `id`      INTEGER NOT NULL AUTO_INCREMENT,
  `user_id` INTEGER NOT NULL,
  `comment` TEXT,
  `deleted` TINYINT(1) NOT NULL DEFAULT 0,
  PRIMARY KEY (`id`),
  CONSTRAINT `fk_comment_user_id` FOREIGN KEY (`user_id`)
    REFERENCES `user` (`id`)
    ON DELETE CASCADE
    ON UPDATE CASCADE
) ENGINE=InnoDB;

这对于强制执行数据完整性非常有用,但我希望能够“删除”用户并保留所有注释(供参考)。

为此,我添加了deleted,以便我可以SET deleted = 1记录。通过默认列出deleted = 0的所有内容,我可以隐藏所有已删除的记录,直到我需要它们为止。

到目前为止一切顺利。

问题出现在:

  • 用户使用用户名(例如“Sam”)注册,
  • 我软删除该用户(出于无关原因)和
  • 还有其他人报名参加Sam,突然间我们违反了user上的UNIQUE约束。

我希望用户能够编辑自己的用户名,因此我不应将username作为主键,删除用户时仍会遇到同样的问题。

有什么想法吗?

编辑以澄清:在下面添加了以下RedFilter的回答和评论。

我担心“已删除”的用户和评论对公众不可见,但仅对管理员可见,或者为了计算统计信息而保留。

这个问题是一个思想实验,用户和评论表只是一个例子。尽管如此,username并不是最好用的; RedFilter提供有关用户身份的有效点,特别是当记录在公共环境中呈现时。

关于“为什么用户名不是主键?”:这只是一个例子,但是如果我将其应用于一个真正的问题,我将需要在一个约束下工作假定存在代理主键的现有系统。

3 个答案:

答案 0 :(得分:26)

在字段上添加唯一约束(用户名,已删除) 将“已删除”的字段类型更改为INTEGER。

在删除操作期间(可以在触发器中或在您需要实际删除用户的部分代码中完成)将id字段的值复制到已删除的字段。

这种方法允许你:

  • 为活跃用户保留唯一名称(已删除= 0)
  • 允许多次删除具有相同用户名的用户

字段'已删除'不能只有2个值,因为以下方案不起作用:

  1. 您创建了用户'Sam'
  2. 用户Sam已删除
  3. 您创建了一个新用户和用户名'Sam'
  4. 您尝试使用userName'Sam'删除用户 - 失败。您已经记录了userName ='Sam'并删除了='1'

答案 1 :(得分:4)

只需在username上保留唯一索引或约束。您不希望新用户能够使用已删除的名称,因为不仅可能存在关于身份的一般混淆,而且如果您仍然显示已删除用户的旧帖子,则会错误地将其发布为具有相同名称的新用户。

当新用户注册时,您通常会在允许注册完成之前检查该名称是否正在使用,因此此处不应存在冲突。

答案 2 :(得分:1)

我对软删除的实用解决方案是通过创建带有以下列的新表进行归档:original_idtable_namepayload(以及可选的主键`id)。< / p>

其中original_id是已删除记录的原始ID,table_name是已删除记录的表名(在您的情况下为"user"),payload是JSON字符串化的删除记录的所有列中的字符串。

我还建议在original_id列上建立索引以供以后的数据检索。

通过这种方式存档数据。您将拥有这些优势

  • 跟踪历史记录中的所有数据
  • 无论删除的记录的表结构如何,只有一个地方可以存储任何表中的记录
  • 不用担心原始表中的唯一索引
  • 不用担心在原始表中检查外来索引

这已经是讨论here,它解释了为什么软删除在实践中不是一个好主意。软删除会在将来引入一些潜在的麻烦,例如计数记录,...