1

使用以下脚本创建的两个表:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

我收到错误:无法创建表 'xxx.user' (errno: 150)

外键错误。

如果我这样做(删除外键约束但仍引用 user_auth):

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL REFERENCES user_auth(user_id) ON DELETE CASCADE,
    PRIMARY KEY(user_id),
)engine=innodb;

一切都很好,但是我可以将 user_id 插入到用户表中,而 user_auth 中没有相应的键,这在我的引用完整性中留下了一个漏洞。

现在踢球说我这样做(删除复合键并使 user_id 成为 user_auth 中的主键):

create table user_auth
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

这也有效,尽管我没有用户名/密码组合来确保唯一性。

我有一种感觉,我错过了 MySQL 工作方式的一些非常关键的东西。请赐教。

谢谢你的时间!

更新

在他们的答案中链接的文章ypercube中,第三点提到PK的顺序和相应的FK必须相同。如果我按以下顺序添加user_id为 PK ,则脚本有效:user_auth

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id, username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

所以我仍然可以SELECT这样,但现在我不能重复用户名/密码组合,因此每个帐户都是唯一的,因为在插入用户数据之前必须存在用户名/密码/user_id 记录。

4

2 回答 2

1

尝试:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_auth_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password)
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    user_username varchar(36) NOT NULL, 
    user_pass varchar(36) NOT NULL, 
    INDEX(user_username, user_pass),
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_username, user_pass) REFERENCES user_auth(username, password) ON DELETE CASCADE
)engine=innodb;

参考:http ://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html

于 2013-01-31T07:33:31.043 回答
1

http://dev.mysql.com/doc/refman/5.5/en/innodb-foreign-key-constraints.html中的第 3 点 说明了一切。因此,如果我添加user_id为 PK user_auth(我想我提到我尝试过这个,但似乎我错过了脚本示例),那么它仍然可能无法正常工作:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(username, password, user_id) -- <== DOES NOT WORK
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

但是,如果我改变顺序...

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id, username, password) -- <== WORKS!
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

因为为了将 user_auth 的 PK 用作 FK,它们必须与 indices 的顺序相同,(如果我有误解请评论)。

但是在表设计方面我们仍然有一个问题,复合键意味着我可以在 user_auth 中有重复的 user_ids,所以更聪明的设计是:

create table user_auth
(
    username varchar(255) NOT NULL,
    password varchar(255) NOT NULL,
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    UNIQUE KEY(username) -- <== I should allow duplicate passwords, so just usernames should be               unique
)engine=innodb;

create table user
(
    user_id varchar(36) NOT NULL,
    PRIMARY KEY(user_id),
    FOREIGN KEY(user_id) REFERENCES user_auth(user_id) ON DELETE CASCADE
)engine=innodb;

好多了

主要的收获是复合键的顺序很重要!

于 2013-01-31T08:02:03.047 回答