MySQL avec des contraintes de suppression douce, de clé Unique et de clé étrangère
Dire que j'ai deux tables, user
et comment
. Ils ont des définitions de table qui ressemblent à ceci:
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;
c'est génial pour faire respecter l'intégrité des données et tout ça, mais je veux pouvoir "supprimer" un utilisateur et garder tous ses commentaires (pour référence).
a cette fin, j'ai ajouté deleted
pour que je puisse SET deleted = 1
sur un disque. Par faire la liste de tout ce deleted = 0
par défaut, je peux cacher tous les enregistrements supprimés jusqu'à ce que j'ai besoin ils.
jusqu'ici tout va bien.
Le problème vient quand:
- Un utilisateur se connecte avec un nom d'utilisateur (par exemple, "Sam"),
- je soft-supprimer l'utilisateur (pour des raisons non liées), et
- Quelqu'un d'autre vient s'inscrire comme Sam, et soudainement nous avons violé la contrainte UNIQUE sur
user
.
je veux que les utilisateurs puissent éditer leurs propres noms d'utilisateur, donc je ne devrais pas faire username
la clé primaire, et nous allons encore ont le même problème lors de la suppression d'utilisateurs.
des idées?
Modifier pour plus de précision: ajouté à la suite de la réponse et des commentaires de RedFilter ci-dessous.
Je m'inquiète du cas où les utilisateurs" supprimés " et les commentaires ne sont pas visibles au public, mais sont seulement des administrateurs visibles, ou sont conservés aux fins du calcul des statistiques.
Cette question est une expérience de pensée, l'utilisateur et le commentaire des tables juste sont des exemples. Encore, username
n'était pas le meilleur à utiliser; RedFilter fait des points valables sur l'identité de l'utilisateur, en particulier lorsque les enregistrements sont présentés dans un contexte public.
Concernant les " pourquoi le nom d'utilisateur n'est-il pas la clé principale?": ce n'est qu'un exemple, mais si je l'applique à un problème réel, j'aurai besoin de travailler dans les contraintes d'un système existant qui suppose l'existence d'une clé primaire de substitution.
2 réponses
ajouter une contrainte unique sur les champs (Nom d'utilisateur, supprimé) Changer le type de champ pour "supprimé" en entier.
pendant l'opération de suppression (cela peut être fait dans trigger, ou dans une partie du code où vous devez supprimer l'utilisateur), copiez la valeur du champ id dans le champ supprimé.
Cette approche permettra de vous:
- conserver des noms uniques pour les utilisateurs actifs (supprimé = 0)
- permet de supprimer des utilisateurs avec le même nom d'utilisateur plusieurs fois
Zone "Supprimé" ne peut pas avoir seulement 2 valeur parce que le scénario suivant ne fonctionnera pas:
- vous créez l'utilisateur 'Sam'
- L'utilisateur Sam est supprimé
- vous créez un nouvel utilisateur avec le nom D'utilisateur 'Sam'
- vous essayez de supprimer l'utilisateur avec le nom d'utilisateur 'Sam' - fail. Vous avez déjà record userName = 'Sam' et deleted = '1'
il suffit de garder l'index unique ou une contrainte sur username
. Vous ne voulez pas que les nouveaux utilisateurs soient en mesure d'utiliser le nom supprimé, car non seulement il pourrait y avoir une confusion générale sur l'identité, mais si vous montrez toujours les anciens messages de l'utilisateur supprimé, alors ils seront compris par erreur être posté par le nouvel utilisateur avec le même nom.
quand un nouvel utilisateur s'enregistre, vous devriez normalement vérifier pour voir si le nom est en usage avant de permettre l'enregistrement pour compléter, donc il devrait y avoir pas de conflit ici.
.