MySQL 的外键与参照完整性

news/2024/7/9 20:41:34 标签: mysql, duplicates, warnings, reference, postgresql, sqlserver
 

1. 什么是参照完整性?
——————–
参照完整性(完整性约束)是数据库设计中的一个重要概念,当数据库中的一个表与一个或多个表进行关联时都会涉及到参照完整性。比如下面这个例子:
文章分类表 -  categories
category_id     name
1               SQL Server
2               Oracle
3               PostgreSQL
5               SQLite

文章表 - articles
article_id      category_id     title
1               1               aa
2               2               bb
3               4               cc

可见以上两个表之间是通过category_id,其中categories表有4条记录,articles表有3条记录。

然而可能因为某种原因我们删掉了categories 表中category_id=4的记录,而articles表却还是有一条 category_id=4的记录,很明显,category_id=4的这条记录不应该存在在articles表中,这样会很容易造成数据错乱。

相反,外键关系(Foreign Key relationships)讨论的是父表(categories)与子表(articles)的关系, 通过引入外键(Foreign Key)这个概念来保证参照完整性(Referential integrity),将使会数据库变的非常简单。比如,要 要做到删除categories表中category_id=4记录的同时删除 articles 表中category_id=4的所有记录,如果没有 引入外键的话,我们就必须执行2条SQL语句才行;如果有外键的话,可以很容易的用一条SQL语句就可以达到要求。

2. 使用外键的条件
—————–
MySQL只在v3.23.34版本以后才引入外键的,所以在这之前的版本就别想了:),除此之外,还必须具备以下几个条件:

    1) 在my.cnf配置文件中打开InnoDB引擎支持。
    # Uncomment the following if you are using InnoDB tables
    innodb_data_home_dir = /var/db/mysql/
    innodb_data_file_path = ibdata1:10M:autoextend
    innodb_log_group_home_dir = /var/db/mysql/
    innodb_log_arch_dir = /var/db/mysql/

    2) 相关联的表都必须采用InnoDB引擎。

    3) 相关联的字段都必须建立所以。
    MySQL v4.0版本以后,定义外键时会自动建立所以,所以在 v4.0 版本以前(含v4.0版本)必须手工定义索引。

    4) 相关联的字段必须采用类似的数据类型,或者说可转换的数据类型,当然相同类型是最好不过了。
    比如父表的字段是TINYINT类型,则子表只能采用TINYINT、SMALLINT、INT、BIGINT等几种类型。

3. 外键语法参考
—————
可以通过 CREATE TABLE 或者 ALTER TABLE 来定义外键。
CREATE TABLE 语法:
CREATE [TEMPORARY] TABLE [IF NOT EXISTS] tbl_name
    [(create_definition,…)]

create_definition:
    column_definition
  | [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,…) [reference_definition]

column_definition:
    col_name type [NOT NULL | NULL] [DEFAULT default_value]
        [AUTO_INCREMENT] [UNIQUE [KEY] | [PRIMARY] KEY]
        [COMMENT ’string’] [reference_definition]

index_col_name:
    col_name [(length)] [ASC | DESC]

reference_definition:
    REFERENCES tbl_name [(index_col_name,…)]
               [MATCH FULL | MATCH PARTIAL | MATCH SIMPLE]
               [ON DELETE reference_option]
               [ON UPDATE reference_option]

reference_option:
    RESTRICT | CASCADE | SET NULL | NO ACTION

ALTER TABLE 语法:
ALTER [IGNORE] TABLE tbl_name
    alter_specification [, alter_specification] …

alter_specification:
  | ADD [CONSTRAINT [symbol]] PRIMARY KEY [index_type] (index_col_name,…)
  | ADD [CONSTRAINT [symbol]] UNIQUE [INDEX] [index_name] [index_type] (index_col_name,…)
  | ADD [CONSTRAINT [symbol]] FOREIGN KEY [index_name] (index_col_name,…) [reference_definition]
  | DROP FOREIGN KEY fk_symbol

4. 定义外键
———–
mysqlCREATE TABLE categories (
    -> category_id tinyint(3) unsigned NOT NULL AUTO_INCREMENT,
    -> name varchar(30) NOT NULL,
    -> PRIMARY KEY(category_id)
    -> ) ENGINE=INNODB;
Query OK, 0 rows affected (0.36 sec)

mysqlINSERT INTO categories VALUES (1, ‘SQL Server’), (2, ‘Oracle’), (3, ‘PostgreSQL’), (4, ‘MySQL’), (5, ‘SQLite’);
Query OK, 5 rows affected (0.48 sec)
Records: 5  Duplicates: 0  Warnings: 0

mysqlCREATE TABLE members (
    -> member_id INT(11) UNSIGNED NOT NULL,
    -> name VARCHAR(20) NOT NULL,
    -> PRIMARY KEY(member_id)
    -> ) ENGINE=INNODB;

Query OK, 0 rows affected (0.55 sec)

mysqlINSERT INTO members VALUES (1, ‘test’), (2, ‘admin’);
Query OK, 2 rows affected (0.44 sec)
Records: 2  Duplicates: 0  Warnings: 0

mysqlCREATE TABLE articles (
    -> article_id INT(11) unsigned NOT NULL AUTO_INCREMENT,
    -> title varchar(255) NOT NULL,
    -> category_id tinyint(3) unsigned NOT NULL,
    -> member_id int(11) unsigned NOT NULL,
    -> INDEX (category_id),
    -> FOREIGN KEY (category_id) REFERENCES categories (category_id),
    -> CONSTRAINT fk_member FOREIGN KEY (member_id) REFERENCES members (member_id),
    -> PRIMARY KEY(article_id)
    -> ) ENGINE=INNODB;

Query OK, 0 rows affected (0.63 sec)

注意:对于非InnoDB表,FOREIGN KEY子句会被忽略掉。
如果遇到如下错误:
ERROR 1005: Can’t create table ‘./test/articles.frm’ (errno: 150)
请仔细检查以下定义语句,常见的错误一般都是表类型不是INNODB、相关联的字段写错了、缺少索引等等。

至此categories.category_id和articles.category_id、members.member_id和 articles.member_id已经建立外键关系,只有 articles.category_id 的值存在 与 categories.category_id 表中并且articles.member_id的值存在与members.member_id表中才 会允许被插入或修改。例如:

mysqlINSERT INTO articles (category_id, member_id, title) VALUES (6, 1, ‘foo’);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test/articles`, CONSTRAINT `articles_ibfk_1` FOREIGN KEY (`category_id`)REFERENCES `categories` (`id`))

mysqlINSERT INTO articles (category_id, member_id, title) VALUES (3, 3, ‘foo’);
ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (`test/articles`, CONSTRAINT `fk_member` FOREIGN KEY (`member_id`) REFERENCES `members` (`member_id`))

可见上面两条语句都会出现错误,因为在categories表中并没有category_id=6、members表中也没有 member_id=3的记录,所以不能插入。而下面这条SQL语句就可以。

mysqlINSERT INTO articles (category_id, member_id, title) VALUES (3, 2, ‘bar’);
Query OK, 1 row affected (0.03 sec)

5. 删除外键定义
—————
不知道大家有没有发现,在前面定义外键的时候articles.member_id外键比articles.category_id子句多了一个 CONSTRAINT fk_member ?
这个fk_member就是用来删除外键定义用的,如下所示:
mysqlALTER TABLE articles DROP FOREIGN KEY fk_member;
Query OK, 1 row affected (0.25 sec)
Records: 1  Duplicates: 0  Warnings: 0

这样articles.member_id外键定义就被删除了,但是如果定义时没有指定CONSTRAINT fk_symbol (即外键符号) 时该怎么删除呢?别急,没有指定时,MySQL会自己创建一个,可以通过以下命令查看:

mysqlSHOW CREATE TABLE articles;
+———-+————————————+
| Table    | Create Table                       |
+———-+————————————+
| articles | CREATE TABLE `articles` (
  `article_id` int(11) unsigned NOT NULL auto_increment,
  `category_id` tinyint(3) unsigned NOT NULL,
  `member_id` int(11) unsigned NOT NULL,
  `title` varchar(255) NOT NULL,
  PRIMARY KEY  (`article_id`),
  KEY `category_id` (`category_id`),
  KEY `member_id` (`member_id`),
  CONSTRAINT `articles_ibfk_1` FOREIGN KEY (`category_id`) REFERENCES `categories` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1          |
+———-+————————————+
1 row in set (0.01 sec)

可以看出articles.category_id的外键符号为articles_ibfk_1,因为就可以执行以下命令删除外键定义:

mysqlALTER TABLE articles DROP FOREIGN KEY articles_ibfk_1;
Query OK, 1 row affected (0.66 sec)
Records: 1  Duplicates: 0  Warnings: 0

6. 总结
——-
引入外键的缺点是会使速度和性能下降,当然外键所带来的优点还有很多,本文仅讨论如何定义、删除外键。至于外键的实际应用将会在以后的文章中介绍


http://www.niftyadmin.cn/n/1050099.html

相关文章

oracle 12cR2 smart flash cache实测

最近一直在处理新系统的性能优化问题,这两天特地测试了下oracle 11gR2开始引入的smart flash cache。 其介绍参考MOS文档,How To Size the Database Smart Flash Cache (文档 ID 1317950.1) The Database Smart Flash Cache is a new feature in Oracle …

TableSpace 的概念及创建

一、TableSpace管理准则 1、使用多个TableSpace * 用户数据与数据字典数据分离,减少竞争 * 应用程序之间的数据分离,防止某个TableSpace脱机后对多个程序造成影响 * 不同磁盘驱动器上存储数据,减少I/O竞争 * 回滚段数据与用户数据分离&a…

bzoj 1237 配对

Written with StackEdit. Description 你有\(n\) 个整数\(A_i\)和\(n\) 个整数\(B_i\)。你需要把它们配对,即每个\(A_i\)恰好对应一 个\(B_i\)。要求所有配对的整数差的绝对值之和尽量小,但不允许两个相同的数配对。例如\(A\){\(5,6,8\)},\(B…

9.6Html

Img width height 单位是px a 超链接 <a href””>百度一下</a> a 两个属性 一个是 href 值是需要跳转的页面地址 另一个是target跳转页面打开的方式 _blank _self(默认的) 备注 Id 是一种起名方式 id”zhangsan” 只要使用id起的名字 前面必须加# #zha…

虚拟机chrome os 没有可用网络错误

从http://chromeos.hexxeh.net/ 下载了一个chrome os的VM版本的&#xff0c;在VM9上打开运行&#xff0c;一直提示没有可用网络 解决方案 查看虚拟机的网络设置设置为 NAT方式查看主机电脑是否可以上网打开---chromeos虚拟机安装目录的 .vmx文件添加 ethernet0.virtualDev &qu…

测试用例实例

1、 一 个好的用例的表述要点&#xff0c;即用例中应当包含的信息 一个优秀的 测试 用例 &#xff0c;应该包含以下信息&#xff1a; 1&#xff09; 软 件或项目的名称 2&#xff09; 软件或项目的版本&#xff08;内部版本号&#xff09; 3&…

让TestDirector支持IE7/IE8

让TestDirector支持IE7/IE8(1)以系统管理员身份登录到TD服务器&#xff1b;(2)找到TD服务器中TDBIN目录&#xff08;缺省情况下是&#xff1a;C:/Inetpub/TDBIN目录&#xff09;&#xff0c;用编辑器打开start_a.htm文件&#xff1b; 注&#xff1a;start_a.htm也有可能在C:/I…

windows下安装msysgit 及ruby

一&#xff1a;安装msysgit git是目前最流行的软件版本控制软件&#xff0c;在window下通常使用msysgit 下载&#xff1a;http://msysgit.github.io/安装&#xff1a;基本上一路默认下一步就行安装之后&#xff0c;可以打开git bash二&#xff1a;安装ruby 目前我使用的是 ruby…