1

我正在重新设计一些应用程序安全日志表(例如用户登录时、访问不同文件等),以解决一些不断变化的需求。它们最初是用 制作的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 文档列出了 6 个选项,但ON DELETE听起来都不合适:

  1. RESTRICT:将阻止 tbl_user 中的删除。
  2. NO ACTION : 像 RESTRICT 一样被评估。
  3. CASCADE:会像我想要的那样在 tbl_user 中删除,但也会在 tbl_login_time 中删除。
  4. SET NULL:将在 tbl_user 中删除,并在 tbl_login_time 中保留该行,但将数据清空。关闭但没有雪茄。
  5. SET DEFAULT : MySQL 识别它,但拒绝它。
  6. 省略 ON DELETE:相当于 RESTRICT。

我以前从未使用过这样的外键(强制但不是),INSERT并且在阅读了很多其他问题之后,似乎其他人也没有这样做。那可能应该告诉我这是错误的方法,但是它可以以某种方式起作用吗?UPDATEDELETE

4

1 回答 1

2

我的问题是我希望为插入强制执行外键,级联更新,但删除 tbl_user 中的记录根本不影响 tbl_login_time。

您无法使用外键约束来实现这一点。

在某些应用程序中,ON DELETE SET NULL 是有意义的。但是您的应用程序本质上是一个存储在 SQL 数据库中的日志文件。您有一个重大问题,您想删除识别信息(用户),但在某些情况下保留他们的 ID 号。坦率地说,我不明白你为什么愿意保留用户 23332 今天 18:40 登录的事实,而不关心你是否能识别用户 23332谁。

你有几个选择。

  • 删除日志文件表,并将日志文件数据存储在文件系统中的文件中,而不是数据库中。如果我站在你的立场上,我会先考虑这个。如果我们谈论的是可以通过 Web 以某种方式访问​​的数据库,请确保日志文件存储在 Web 根目录之外。(我会将它与所有其他日志文件一起存储在 /var/log 下。)
  • 使用外键约束,永远不要删除用户。
  • 使用外键约束,并使用 ON DELETE SET NULL 或 ON DELETE SET DEFAULT 的效果。在这个特定的应用程序中,ON DELETE SET NULL 和 ON DELETE SET DEFAULT 在语义上是等价的。两者都用无法识别用户的数据替换好的数据。如果您无论如何都无法识别用户 23332,谁在乎您是否知道她在今天 18:40 登录?
  • 删除外键约束,并使用触发器来做任何你喜欢的事情。

我很确定我们同意最明显的选择——使用带有 ON DELETE CASCADE 的外键——对您的应用程序来说是完全错误的。

于 2013-01-28T22:08:54.657 回答