【发布时间】:2013-01-28 21:07:41
【问题描述】:
我正在重新设计一些应用程序安全日志表(例如用户登录时、访问不同文件等),以满足一些不断变化的需求。它们最初是用MyISAM 制作的,但并不经常被访问,切换到InnoDB 并添加一堆外键以确保数据完整性确实会更有益。由于无论如何我都必须重新制作桌子,我认为现在是进行转换的好时机。
在大多数情况下,一切都是简单的外键并且按预期工作。我尝试一些奇怪的东西并遇到问题的唯一部分是 user_ids。这些日志表中的每条记录都与一个 user_id 相关联,我想确保在插入记录时存在给定的 user_id。添加引用用户表的外键解决了这个问题 - 简单的东西。以下是一些简洁、有代表性的表格:
用户表
CREATE TABLE tbl_user (
id INT(10) NOT NULL AUTO_INCREMENT,
first_name VARCHAR(50),
PRIMARY KEY(id)
) ENGINE=InnoDB;
示例日志表
CREATE TABLE tbl_login_time (
id INT(10) NOT NULL AUTO_INCREMENT,
user_id INT(10) NOT NULL,
login_at TIMESTAMP NOT NULL,
PRIMARY KEY(id),
CONSTRAINT 'tbl_login_time_fk_1` FOREIGN KEY (user_id) REFERENCES tbl_user
ON UPDATE CASCADE ON DELETE ???
) ENGINE=InnoDB;
我的问题是我希望为插入强制执行外键,级联更新,但删除 tbl_user 中的记录根本不影响 tbl_login_time。通常用户会被标记为不活动,但每隔一段时间就会有一个用户被完全删除,但需要维护日志。
MySQL docs 列出了 ON DELETE 的 6 个选项,但听起来都不合适:
- RESTRICT:会阻止 tbl_user 中的删除。
- NO ACTION:像 RESTRICT 一样进行评估。
- CASCADE:会按照我的意愿在 tbl_user 中删除,但也会在 tbl_login_time 中删除。
- SET NULL:将在 tbl_user 中删除,并在 tbl_login_time 中保留该行但将数据清空。关闭但没有雪茄。
- SET DEFAULT:MySQL 识别它,但拒绝它。
- Omit ON DELETE:相当于 RESTRICT。
我以前从未使用过这样的外键(强制执行INSERT 和UPDATE,但不是DELETE),在阅读了很多其他问题之后,似乎其他人也没有这样做。那可能应该告诉我这是错误的方法,但它可以以某种方式工作吗?
【问题讨论】:
-
你能用触发器吗?
-
@njk 如果需要,我可以将触发器添加到用户表,但通常我会尽可能避免使用它们。如果事实证明您无法使用外键进行这项工作并且必须使用触发器,那将是一个可以接受的答案。
-
删除用户记录,同时留下带有 ID 引用的日志似乎不太实用。对我来说似乎是一个设计缺陷。如果您需要保留日志,为什么不使用一些停用标志/摆脱用户日志依赖?
-
@rosipov 经过一番研究并在这里看到了前两个 cmets,我认为这可能不是正确的方法。使用触发器确保只输入有效数据可能是可行的方法,但我仍然很好奇你能用外键完成这个吗?
-
外键管理依赖关系(A 必须依赖于 B),您试图忽略这一事实(A 必须依赖于 B,除非没有 B)。我将以这种方式使用外键的技术方面留给专家。但是:我真的不喜欢在日志表中没有用户的用户 ID 的想法——一旦用户被删除,它就会变成垃圾数据。底线 - 您很少希望完全删除生产应用程序中的数据。
标签: mysql database-design foreign-keys