Mysql之约束下篇
自增列(AUTO_INCREMENT)
自增列的作用:就是让某个字段的值自增自增
关键字
AUTO_INCREMENT
特点和要求
(1)一个表最多只能有一个自增长列
(2)当需要产生唯一标识符或顺序值时,可设置自增长
(3)自增长列约束的列必须是键列(主键列,唯一键列)
(4)自增约束的列的数据类型必须是整数类型
(5)如果自增列指定了 0 和 null,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接赋值为具体值。
添加自增约束
在数据类型后面或者约束后面加上AUTO_INCREMENT 就行
也分两种情况:
情况一:建表的时候,添加自增列
情况二:在建表之后,添加约束
错误演示
create table employee
(
eid int auto_increment,
ename varchar(20)
);
# ERROR 1075 (42000): Incorrect table definition; there can be only one auto column
and it must be defined as a key
create table employee(
eid int primary key,
ename varchar(20) unique key auto_increment
);
# ERROR 1063 (42000): Incorrect column specifier for column 'ename' 因为ename不是整数类
型
#情况一:
CREATE TABLE 表名
(
数据段 数据类型 约束类型 AUTO_INCREMENT
)
案例
CREATE TABLE student8
(
id INT PRIMARY KEY AUTO_INCREMENT,
name varchar(20)
)
DESC student8
情况二:
ALTER TABLE 表名称
MODIFY 字段名 数据类型 AUTO_INCREMENT;
案例
CREATE TABLE student10
(
id INT PRIMARY KEY,
name varchar(20)
)
ALTER TABLE student10 MODIFY id INT AUTO_INCREMENT
当然这里注意:
修改的时候,不必加上变量名的约束类型,只用加上变量名的约束类型就行。
删除自增约束
去掉AUTO_INCREMENT,就相当于删除自增约束
alter table 表名称 modify 字段名 数据类型;
#去掉auto_increment相当于删除
案例
ALTER TABLE student10 MODIFY id INT;
DESC student10
Mysql8.0新特性-自增变量的持久化
Mysql8.0以前的版本
CREATE TABLE student11
(
id INT PRIMARY KEY AUTO_INCREMENT
)
INSERT INTO student11
VALUES(0),(0),(0),(0);
SELECT * FROM student11
当删除一4,然后再插入一个,插入的数变成了5
SELECT * FROM student11
DELETE FROM student11 WHERE id = 4
INSERT INTO student11 VALUES(0)
SELECT * FROM student11
此时重启数据库,然后在插入一个空值
此时插入的值却是4,但是根据逻辑此时插入的数应该会是6,那么为什么会出现这种情况呢?
主要原因是自增主键没有持久化。 在MySQL 5.7系统中,对于自增主键的分配规则,是由InnoDB数据字典内部一个 计数器 来决定的,而该计数器只在 内存中维护 ,并不会持久化到磁盘中。当数据库重启时,该计数器会被初始化 。
在Mysql8.0以后的版本
从结果可以看出来,自增变量已经持久化了
MySQL 8.0将自增主键的计数器持久化到 重做日志 中。每次计数器发生改变,都会将其写入重做日志中。如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值
FOREIGN KEY 约束
作用:
限定某个表的某个字段的引用完整性。
关键字
FOREIGN KEY
主表和从表/父表和子表
主表(父表):被引用的表,被参考的表
从表(子表):引用别人的表,参考别人的表
例如:员工表的员工所在部门这个字段的值要参考部门表:部门表是主表,员工表是从表。
例如:学生表、课程表、选课表:选课表的学生和课程要分别参考学生表和课程表,学生表和课程表是主表,选课表是从表。
特点
1.从表的外键列**,必须引用/参考主表的主键或唯一约束的列**
(因为因为被依赖/被参考的值必须是唯一的)
2.在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名(例如student_ibfk_1;),也可以指定外键约束)
3.创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表
4.删表时,先删从表(或先删除外键约束),再删除主表
5.当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,然后才可以删除主表的数据。
6.在“从表”中指定外键约束,并且一个表可以建立多个外键约束。
7.从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类型不一样,创建子表时,就会出现错误“ERROR 1005 (HY000): Can’t createtable’database.tablename’(errno: 150)”。
8.删除外键约束后,必须 手动 删除对应的索引
添加外键约束
情况一:建表的时候,添加约束
#语法格式:
create table 主表名称(
字段1 数据类型 primary key,
字段2 数据类型
);
create table 从表名称(
字段1 数据类型 primary key,
字段2 数据类型,
[CONSTRAINT <外键约束名称>] FOREIGN KEY(从表的某个字段) references 主表名(被参考字段)
);
#(从表的某个字段)的数据类型必须与主表名(被参考字段)的数据类型一致,逻辑意义也一样
#(从表的某个字段)的字段名可以与主表名(被参考字段)的字段名一样,也可以不一样
-- FOREIGN KEY: 在表级指定子表中的列
-- REFERENCES: 标示在父表中的列
案例
CREATE TABLE dep
(
dep_id INT PRIMARY KEY,
dep_name varchar(20)
)
CREATE TABLE emp
(
emp_id INT PRIMARY KEY,
emp_name VARCHAR(20),
FOREIGN KEY(emp_id) REFERENCES dep(dep_id)
)
desc emp
注意:约束这里需要加上主表名,不需要加上从表名
情况二:建表之后,添加约束
REATE TABLE dep1
(
dep1_id INT PRIMARY KEY
)
CREATE TABLE emp1
(
emp1_id INT PRIMARY KEY
)
ALTER TABLE emp1
ADD FOREIGN KEY(emp1_id) REFERENCES dep1(dep1_id)
要注意: 要添加外键约束,必须要有唯一性约束或者主键约束
约束等级
1.Cascade方式 :在父表上update/delete记录时,同步update/delete掉子表的匹配记录
2.Set null方式 :在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
3.No action方式 :如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
4.Restrict方式 :同no action, 都是立即检查外键约束
5.Set default方式 (在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别
如果没有指定等级,就相当于Restrict方式。
对于外键约束,最好是采用: ON UPDATE CASCADE ON DELETERESTRICT 的方式
#语法格式:
create table 主表名称(
字段1 数据类型 primary key,
字段2 数据类型
);
create table 从表名称(
字段1 数据类型 primary key,
字段2 数据类型,
[CONSTRAINT <外键约束名称>] FOREIGN KEY(从表的某个字段) references 主表名(被参考字段)
) ON UPDATE CASCADE ON DELETERESTRICT;
作用也就是同步更新,主表更新了,从表也更新
建表之后添加也一样,在之前的ALTER的语句后面加上,ON UPDATE CASCADE ON DELETERESTRICT,这句就行
删除外键约束
删除表的时候,要注意删除表的顺序,先删除从表再删除主表
删除外键约束时候,先删除删除外键约束,然后再删除索引
注意:索引只能手动删除
(1)第一步先查看约束名和删除外键约束
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';#查看某个
表的约束名
ALTER TABLE 从表名 DROP FOREIGN KEY 外键约束名;
(2)第二步查看索引名和删除索引。(注意,只能手动删除)
SHOW INDEX FROM 表名称; #查看某个表的索引名
ALTER TABLE 从表名 DROP INDEX 索引名;
mysql> SELECT * FROM information_schema.table_constraints WHERE table_name = 'emp';
mysql> alter table emp drop foreign key emp_ibfk_1;
Query OK, 0 rows affected (0.02 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from emp;
mysql> alter table emp drop index deptid;
Query OK, 0 rows affected (0.01 sec)
Records: 0 Duplicates: 0 Warnings: 0
mysql> show index from emp;
面试问题
问题1:如果两个表之间有关系(一对一、一对多),比如:员工表和部门表(一对多),它们之间是否一定要建外键约束?
答:不是的
问题2:建和不建外键约束有什么区别?
答:建外键约束,你的操作(创建表、删除表、添加、修改、删除)会受到限制,从语法层面受到限制。例如:在员工表中不可能添加一个员工信息,它的部门的值在部门表中找不到。
不建外键约束,你的操作(创建表、删除表、添加、修改、删除)不受限制,要保证数据的 引用完整性 ,只能依 靠程序员的自觉 ,或者是 在Java程序中进行限定 。例如:在员工表中,可以添加一个员工的信息,它的部门指定为一个完全不存在的部门。
问题3:那么建和不建外键约束和查询有没有关系?
答:没有
在 MySQL 里,外键约束是有成本的,需要消耗系统资源。对于大并发的 SQL 操作,有可能会不适合。比如大型网站的中央数据库,可能会 因为外键约束的系统开销而变得非常慢 。所以, MySQL 允许你不使用系统自带的外键约束,在 应用层面 完成检查数据一致性的逻辑。也就是说,即使你不用外键约束,也要想办法通过应用层面的附加逻辑,来实现外键约束的功能,确保数据的一致性。
DEFAULT约束
作用
给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值。
关键字
关键字:DEFAULT
添加默认值约束
注意:说明:默认值约束一般不在唯一键和主键列上加
前面讲约束举了很多例子,用法都差不多,这里就不在举例了,说明下语法格式
情况一:建表的时候添加默认值约束
#语法格式:
create table 表名称(
字段名 数据类型 primary key,
字段名 数据类型 unique key not null,
字段名 数据类型 unique key,
字段名 数据类型 not null default 默认值,
);
情况二:建表之后,添加默认值约束
alter table 表名称 modify 字段名 数据类型 default 默认值;
#如果这个字段原来有非空约束,你还保留非空约束,那么在加默认值约束时,还得保留非空约束,否则非空约束就被删除了
#同理,在给某个字段加非空约束也一样,如果这个字段原来有默认值约束,你想保留,也要在modify语句中保留默认值约束,否则就删除了
alter table 表名称 modify 字段名 数据类型 default 默认值 not null;
删除默认值约束
alter table 表名称 modify 字段名 数据类型 ;#删除默认值约束,也不保留非空约束
alter table 表名称 modify 字段名 数据类型 not null; #删除默认值约束,保留非空约束
CHECK约束
作用
作用:检查某个字段的值是否符号xx要求,一般指的是值的范围
注意:MySQL5.7 可以使用check约束,但check约束对数据验证没有任何作用。添加数据时,没有任何错误或警告但是MySQL 8.0中可以使用check约束了。
关键字
CHECK约束
案例
这个CHECK约束不是特别重要,就简单了解下就行
CREATE TABLE temp
(
id INT AUTO_INCREMENT,
NAME VARCHAR(20),
age INT CHECK(age > 20),
PRIMARY KEY(id)
)
这个案例就是检查age是否是大于20的,
如果添加的信息age小于20那么就会添加信息失败
如果添加的信age大于20那么信息回添加成功
面试问题
面试1、为什么建表时,加 not null default ‘’ 或 default 0
答:不想让表中出现null值。
面试2、为什么不想要 null 的值 答: (1)不好比较。null是一种特殊值,比较时只能用专门的is null 和 is not
null来比较。碰到运算符,通常返回null。 (2)效率不高。影响提高索引效果。因此,我们往往在建表时 not null default’’ 或 default 0
面试3、带AUTO_INCREMENT约束的字段值是从1开始的吗?
在MySQL中,默认AUTO_INCREMENT的初始值是1,每新增一条记录,字段值自动加1。设置自增属性(AUTO_INCREMENT)的时候,还可以指定第一条插入记录的自增字段的值,这样新插入的记录的自增字段值从初始值开始递增,如在表中插入第一条记录,同时指定id值为5,则以后插入的记录的id值就会从6开始往上增加。添加主键约束时,往往需要设置字段自动增加属性。面试4、并不是每个表都可以任意选择存储引擎? 外键约束(FOREIGN KEY)不能跨引擎使用。
MySQL支持多种存储引擎,每一个表都可以指定一个不同的存储引擎,需要注意的是:外键约束是用来保证数据的参照完整性的,如果表之间需要关联外键,却指定了不同的存储引擎,那么这些表之间是不能创建外键约束的。所以说,存储引擎的选择也不完全是随意的。