十一.约束(二)

约束

  • 5.自增列:AUTO_INCREMENT
    • 5.1作用
    • 5.2关键字
    • 5.3特点和要求
    • 5.4如何指定自增约束
    • 5.5如何删除自增列
    • 5.6MySQL8.0新特性——自增变量的持久化
  • 6.FOREIGN KEY 约束
    • 6.1作用
    • 6.2关键字
    • 6.3主表和从表/父表和子表
    • 6.4特点
    • 6.5添加外键约束
    • 6.6演示问题
    • 6.7约束等级
    • 6.8删除外键约束
    • 6.9开发场景
    • 6.10阿里开发规范
  • 7.CHECK约束
    • 7.1作用
    • 7.2关键字
    • 7.3说明MySQL5.7不支持
  • 8.DEFAULT约束
    • 8.1作用
    • 8.2关键字
    • 8.3如何给字段加默认值
    • 8.4如何删除默认值约束
  • 9.面试

5.自增列:AUTO_INCREMENT

5.1作用

某个字段的值自增

5.2关键字

auto_increment

5.3特点和要求

  • 一个表最多只能有一个自增长列
  • 当需要产生唯一标识符或顺序值时,可设置自增长
  • 自增长列约束的列必须是键列(主键列,唯一键列)
  • 自增约束的列的数据类型必须是整数类型
  • 如果自增列指定了 0 和 null,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接赋值为具体值。

错误演示:

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不是整数类型

5.4如何指定自增约束

(1)建表时

create table 表名称(字段名  数据类型  primary key auto_increment,字段名  数据类型  unique key not null,  字段名  数据类型  unique key,字段名  数据类型  not null default 默认值, 
);create table 表名称(字段名  数据类型 default 默认值 ,字段名  数据类型 unique key auto_increment,  字段名  数据类型 not null default 默认值,,primary key(字段名)
);
create table employee(eid int primary key auto_increment,ename varchar(20)
);mysql> desc employee;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(11)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

(2)建表后

alter table 表名称 modify 字段名 数据类型 auto_increment;

举例:

create table employee(eid int primary key ,ename varchar(20)
);alter table employee modify eid int auto_increment;mysql> desc employee;
+-------+-------------+------+-----+---------+----------------+
| Field | Type        | Null | Key | Default | Extra          |
+-------+-------------+------+-----+---------+----------------+
| eid   | int(11)     | NO   | PRI | NULL    | auto_increment |
| ename | varchar(20) | YES  |     | NULL    |                |
+-------+-------------+------+-----+---------+----------------+
2 rows in set (0.00 sec)

5.5如何删除自增列

#alter table 表名称 modify 字段名 数据类型 auto_increment;#给这个字段增加自增约束
alter table 表名称 modify 字段名 数据类型; #去掉auto_increment相当于删除
alter table employee modify eid int;mysql> desc employee;
+-------+-------------+------+-----+---------+-------+
| Field | Type        | Null | Key | Default | Extra |
+-------+-------------+------+-----+---------+-------+
| eid   | int(11)     | NO   | PRI | NULL    |       |
| ename | varchar(20) | YES  |     | NULL    |       |
+-------+-------------+------+-----+---------+-------+
2 rows in set (0.00 sec)

5.6MySQL8.0新特性——自增变量的持久化

在MySQL 8.0之前,自增主键AUTO_INCREMENT的值如果大于max(primary key)+1,在MySQL重启后,会重置AUTO_INCREMENT=max(primary key)+1,这种现象在某些情况下会导致业务主键冲突或者其他难以发现的问题。
下面通过案例来对比不同的版本中自增变量是否持久化。
在MySQL 5.7版本中,测试步骤如下:
创建的数据表中包含自增主键的id字段,语句如下:

CREATE TABLE test1(
id INT PRIMARY KEY AUTO_INCREMENT
);

插入4个空值,执行如下:

INSERT INTO test1
VALUES(0),(0),(0),(0);

查询数据表中test1的数据,结果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
4 rows in set (0.00 sec)

删除id为4的记录,语句如下:

DELETE FROM test1 WHERE id = 4;

再次插入一个空值,语句如下:

INSERT INTO test1 VALUES(0);

查询此时数据表test1中的数据,结果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  5 |
+----+
4 rows in set (0.00 sec)

从结果可以看出,虽然删除了id为4的记录,但是再次插入空值时,并没有重用被删除的4,而是分配了5。
删除id为5的记录,结果如下

DELETE FROM test1 where id=5;

重启数据库,重新插入一个空值。

INSERT INTO test1 values(0);

再次查询数据表test1中的数据,结果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  4 |
+----+
4 rows in set (0.00 sec)

从结果可以看出,新插入的0值分配的是4,按照重启前的操作逻辑,此处应该分配6。出现上述结果的主要原因是自增主键没有持久化。
在MySQL 5.7系统中,对于自增主键的分配规则,是由InnoDB数据字典内部一个计数器来决定的,而该计数器只在内存中维护,并不会持久化到磁盘中。当数据库重启时,该计数器会被初始化。

在MySQL 8.0版本中,上述测试步骤最后一步的结果如下:

mysql> SELECT * FROM test1;
+----+
| id |
+----+
|  1 |
|  2 |
|  3 |
|  6 |
+----+
4 rows in set (0.00 sec)

从结果可以看出,自增变量已经持久化了。

MySQL 8.0将自增主键的计数器持久化到重做日志中。每次计数器发生改变,都会将其写入重做日志中。如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值。

6.FOREIGN KEY 约束

6.1作用

限定某个表的某个字段的引用完整性。
比如:员工表的员工所在部门的选择,必须在部门表中找到对应的部分。在这里插入图片描述

6.2关键字

foreign key

6.3主表和从表/父表和子表

主表(父表):被引用的表,被参考的表

从表(子表):引用别人的表,参考别人的表

例如:员工表的员工所在部门这个字段的值要参考部门表:部门表是主表,员工表是从表。

例如:学生表、课程表、选课表:选课表的学生和课程要分别参考学生表和课程表,学生表和课程表是主表,选课表是从表。

6.4特点

  • 从表的外键列,必须引用/参考主表的主键或唯一约束的列
    • 为什么?因为被依赖/被参考的值必须是唯一的
  • 在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名(例如 student_ibfk_1;),也可以指定外键约束名。
  • 创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表
  • 删表时,先删从表(或先删除外键约束),再删除主表
  • 当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,然后才可以删除主表的数据
  • 在“从表”中指定外键约束,并且一个表可以建立多个外键约束
  • 从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类型不一样,创建子表时,就会出现错误“ERROR 1005 (HY000): Can’t create table’database.tablename’(errno: 150)”。
    ​ 例如:都是表示部门编号,都是int类型。
  • 当创建外键约束时,系统默认会在所在的列上建立对应的普通索引。但是索引名是外键的约束名。(根据外键查询效率很高)
  • 删除外键约束后,必须手动删除对应的索引

6.5添加外键约束

(1)建表时

create table 主表名称(字段1  数据类型  primary key,字段2  数据类型
);create table 从表名称(字段1  数据类型  primary key,字段2  数据类型,[CONSTRAINT <外键约束名称>] FOREIGN KEY(从表的某个字段) references 主表名(被参考字段)
);
#(从表的某个字段)的数据类型必须与主表名(被参考字段)的数据类型一致,逻辑意义也一样
#(从表的某个字段)的字段名可以与主表名(被参考字段)的字段名一样,也可以不一样-- FOREIGN KEY: 在表级指定子表中的列
-- REFERENCES: 标示在父表中的列
create table dept( #主表did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(#从表eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)   #在从表中指定外键约束#emp表的deptid和和dept表的did的数据类型一致,意义都是表示部门的编号
);说明:
(1)主表dept必须先创建成功,然后才能创建emp表,指定外键成功。
(2)删除表时,先删除从表emp,再删除主表dept

(2)建表后
一般情况下,表与表的关联都是提前设计好了的,因此,会在创建表的时候就把外键约束定义好。不过,如果需要修改表的设计(比如添加新的字段,增加新的关联关系),但没有预先定义外键约束,那么,就要用修改表的方式来补充定义。

ALTER TABLE 从表名 ADD [CONSTRAINT 约束名] FOREIGN KEY (从表的字段) REFERENCES 主表名(被引用字段) [on update xx][on delete xx];

举例:

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int				#员工所在的部门
);
#这两个表创建时,没有指定外键的话,那么创建顺序是随意alter table emp add foreign key (deptid) references dept(did);

6.6演示问题

(1)失败:不是键列

create table dept(did int ,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)
);
#ERROR 1215 (HY000): Cannot add foreign key constraint  原因是dept的did不是键列

(2)失败:数据类型不一致

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid char,				#员工所在的部门foreign key (deptid) references dept(did)
);
#ERROR 1215 (HY000): Cannot add foreign key constraint  原因是从表的deptid字段和主表的did字段的数据类型不一致,并且要它俩的逻辑意义一致

(3)成功,两个表字段名一样

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名did int,				#员工所在的部门foreign key (did) references dept(did)  #emp表的deptid和和dept表的did的数据类型一致,意义都是表示部门的编号#是否重名没问题,因为两个did在不同的表中
);

(4)添加、删除、修改问题

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)  #emp表的deptid和和dept表的did的数据类型一致,意义都是表示部门的编号
);
insert into dept values(1001,'教学部');
insert into dept values(1003, '财务部');insert into emp values(1,'张三',1001); #添加从表记录成功,在添加这条记录时,要求部门表有1001部门insert into emp values(2,'李四',1005);#添加从表记录失败
ERROR 1452 (23000): Cannot add(添加) or update(修改) a child row: a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`)) 从表emp添加记录失败,因为主表dept没有1005部门mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部  |
| 1003 | 财务部  |
+------+--------+
2 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三   |   1001 |
+-----+-------+--------+
1 row in set (0.00 sec)
update emp set deptid = 1002 where eid = 1;#修改从表失败 
ERROR 1452 (23000): Cannot add(添加) or update(修改) a child row(子表的记录): a foreign key constraint fails(外键约束失败) (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`))  #部门表did字段现在没有1002的值,所以员工表中不能修改员工所在部门deptid为1002update dept set did = 1002 where did = 1001;#修改主表失败
ERROR 1451 (23000): Cannot delete(删除) or update(修改) a parent row(父表的记录): a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`)) #部门表did的1001字段已经被emp引用了,所以部门表的1001字段就不能修改了。update dept set did = 1002 where did = 1003;#修改主表成功  因为部门表的1003部门没有被emp表引用,所以可以修改
delete from dept where did=1001; #删除主表失败
ERROR 1451 (23000): Cannot delete(删除) or update(修改) a parent row(父表记录): a foreign key constraint fails (`atguigudb`.`emp`, CONSTRAINT `emp_ibfk_1` FOREIGN KEY (`deptid`) REFERENCES `dept` (`did`))  #因为部门表did的1001字段已经被emp引用了,所以部门表的1001字段对应的记录就不能被删除

总结:约束关系是针对双方的

  • 添加了外键约束后,主表的修改和删除数据受约束
  • 添加了外键约束后,从表的添加和修改数据受约束
  • 在从表上建立外键,要求主表必须存在
  • 删除主表时,要求从表从表先删除,或将从表中外键引用该主表的关系先删除

6.7约束等级

  • Cascade方式:在父表上update/delete记录时,同步update/delete掉子表的匹配记录
  • Set null方式:在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
  • No action方式:如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
  • Restrict方式:同no action, 都是立即检查外键约束
  • Set default方式(在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别

如果没有指定等级,就相当于Restrict方式。

对于外键约束,最好是采用: ON UPDATE CASCADE ON DELETE RESTRICT 的方式。
(1)演示1:on update cascade on delete set null:

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)  on update cascade on delete set null#把修改操作设置为级联修改等级,把删除操作设置为set null等级
);
insert into dept values(1001,'教学部');
insert into dept values(1002, '财务部');
insert into dept values(1003, '咨询部');insert into emp values(1,'张三',1001); #在添加这条记录时,要求部门表有1001部门
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1002 | 财务部 |
| 1003 | 咨询部 |
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1002 |
+-----+-------+--------+
3 rows in set (0.00 sec)
#修改主表成功,从表也跟着修改,修改了主表被引用的字段1002为1004,从表的引用字段就跟着修改为1004了
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1003 | 咨询部 |
| 1004 | 财务部 | #原来是1002,修改为1004
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1004 | #原来是1002,跟着修改为1004
+-----+-------+--------+
3 rows in set (0.00 sec)
#删除主表的记录成功,从表对应的字段的值被修改为null
mysql> delete from dept where did = 1001;
Query OK, 1 row affected (0.01 sec)mysql> select * from dept;
+------+--------+
| did  | dname  | #记录1001部门被删除了
+------+--------+
| 1003 | 咨询部  |
| 1004 | 财务部  |
+------+--------+
2 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   NULL | #原来引用1001部门的员工,deptid字段变为null
|   2 | 李四  |   NULL |
|   3 | 王五  |   1004 |
+-----+-------+--------+
3 rows in set (0.00 sec)

(2)演示2:on update set null on delete cascade:

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)  on update set null on delete cascade#把修改操作设置为set null等级,把删除操作设置为级联删除等级
);
insert into dept values(1001,'教学部');
insert into dept values(1002, '财务部');
insert into dept values(1003, '咨询部');insert into emp values(1,'张三',1001); #在添加这条记录时,要求部门表有1001部门
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1002 | 财务部 |
| 1003 | 咨询部 |
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1002 |
+-----+-------+--------+
3 rows in set (0.00 sec)
#修改主表,从表对应的字段设置为null
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1003 | 咨询部 |
| 1004 | 财务部 | #原来did是1002
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   NULL | #原来deptid是1002,因为部门表1002被修改了,1002没有对应的了,就设置为null
+-----+-------+--------+
3 rows in set (0.00 sec)
#删除主表的记录成功,主表的1001行被删除了,从表相应的记录也被删除了
mysql> delete from dept where did=1001;
Query OK, 1 row affected (0.00 sec)mysql> select * from dept;
+------+--------+
| did  | dname  | #部门表中1001部门被删除
+------+--------+
| 1003 | 咨询部 |
| 1004 | 财务部 |
+------+--------+
2 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |#原来1001部门的员工也被删除了
+-----+-------+--------+
|   3 | 王五  |   NULL |
+-----+-------+--------+
1 row in set (0.00 sec)

(3)演示:on update cascade on delete cascade

create table dept(did int primary key,		#部门编号dname varchar(50)			#部门名称
);create table emp(eid int primary key,  #员工编号ename varchar(5),     #员工姓名deptid int,				#员工所在的部门foreign key (deptid) references dept(did)  on update cascade on delete cascade#把修改操作设置为级联修改等级,把删除操作也设置为级联删除等级
);
insert into dept values(1001,'教学部');
insert into dept values(1002, '财务部');
insert into dept values(1003, '咨询部');insert into emp values(1,'张三',1001); #在添加这条记录时,要求部门表有1001部门
insert into emp values(2,'李四',1001);
insert into emp values(3,'王五',1002);
mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1002 | 财务部 |
| 1003 | 咨询部 |
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1002 |
+-----+-------+--------+
3 rows in set (0.00 sec)
#修改主表,从表对应的字段自动修改
mysql> update dept set did = 1004 where did = 1002;
Query OK, 1 row affected (0.00 sec)
Rows matched: 1  Changed: 1  Warnings: 0mysql> select * from dept;
+------+--------+
| did  | dname  |
+------+--------+
| 1001 | 教学部 |
| 1003 | 咨询部 |
| 1004 | 财务部 | #部门1002修改为1004
+------+--------+
3 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |
+-----+-------+--------+
|   1 | 张三  |   1001 |
|   2 | 李四  |   1001 |
|   3 | 王五  |   1004 | #级联修改
+-----+-------+--------+
3 rows in set (0.00 sec)
#删除主表的记录成功,主表的1001行被删除了,从表相应的记录也被删除了
mysql> delete from dept where did=1001;
Query OK, 1 row affected (0.00 sec)mysql> select * from dept;
+------+--------+
| did  | dname  | #1001部门被删除了
+------+--------+
| 1003 | 咨询部 |
| 1004 | 财务部 | 
+------+--------+
2 rows in set (0.00 sec)mysql> select * from emp;
+-----+-------+--------+
| eid | ename | deptid |  #1001部门的员工也被删除了
+-----+-------+--------+
|   3 | 王五  |   1004 |
+-----+-------+--------+
1 row in set (0.00 sec)

6.8删除外键约束

流程如下:

(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: 0mysql> 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

6.9开发场景

问题1:如果两个表之间有关系(一对一、一对多),比如:员工表和部门表(一对多),它们之间是否一定要建外键约束?
答:不是的

问题2:建和不建外键约束有什么区别?
答:建外键约束,你的操作(创建表、删除表、添加、修改、删除)会受到限制,从语法层面受到限制。例如:在员工表中不可能添加一个员工信息,它的部门的值在部门表中找不到。

不建外键约束,你的操作(创建表、删除表、添加、修改、删除)不受限制,要保证数据的引用完整性,只能依靠程序员的自觉,或者是在Java程序中进行限定。例如:在员工表中,可以添加一个员工的信息,它的部门指定为一个完全不存在的部门。

问题3:那么建和不建外键约束和查询有没有关系?
答:没有

在 MySQL 里,外键约束是有成本的,需要消耗系统资源。对于大并发的 SQL 操作,有可能会不适合。比如大型网站的中央数据库,可能会因为外键约束的系统开销而变得非常慢。所以, MySQL 允许你不使用系统自带的外键约束,在应用层面完成检查数据一致性的逻辑。也就是说,即使你不用外键约束,也要想办法通过应用层面的附加逻辑,来实现外键约束的功能,确保数据的一致性。

6.10阿里开发规范

强制】不得使用外键与级联,一切外键概念必须在应用层解决。

说明:(概念解释)学生表中的 student_id 是主键,那么成绩表中的 student_id 则为外键。如果更新学生表中的 student_id,同时触发成绩表中的 student_id 更新,即为级联更新。外键与级联更新适用于单机低并发,不适合分布式高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度

7.CHECK约束

7.1作用

检查某个字段的值是否符合xx要求,一般指的是范围

7.2关键字

check

7.3说明MySQL5.7不支持

MySQL5.7 可以使用check约束,但check约束对数据验证没有任何作用。添加数据时,没有任何错误或警告

但是MySQL 8.0中可以使用check约束了

create table employee(eid int primary key,ename varchar(5),gender char check ('男' or '女')
);insert into employee values(1,'张三','妖');mysql> select * from employee;
+-----+-------+--------+
| eid | ename | gender |
+-----+-------+--------+
|   1 | 张三   ||
+-----+-------+--------+
1 row in set (0.00 sec)

举例:

CREATE TABLE temp(
id INT AUTO_INCREMENT,
NAME VARCHAR(20),
age INT CHECK(age > 20),
PRIMARY KEY(id)
);age tinyint check(age >20) 或 sex char(2) check(sex in(‘男’,’女’))CHECK(height>=0 AND height<3)

8.DEFAULT约束

8.1作用

给某个字段/某列指定默认值,一旦设置默认值,在插入数据时,如果此字段没有显示赋值,泽赋值为默认值。

8.2关键字

default

8.3如何给字段加默认值

(1)建表时

create table 表名称(字段名  数据类型  primary key,字段名  数据类型  unique key not null,  字段名  数据类型  unique key,字段名  数据类型  not null default 默认值, 
);
create table 表名称(字段名  数据类型 default 默认值 ,字段名  数据类型 not null default 默认值,  字段名  数据类型 not null default 默认值,primary key(字段名),unique key(字段名)
);说明:默认值约束一般不在唯一键和主键列上加
create table employee(eid int primary key,ename varchar(20) not null,gender char default '男',tel char(11) not null default '' #默认是空字符串
);
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | NO   |     | NULL    |       |
| gender | char(1)     | YES  |     ||       |
| tel    | char(11)    | NO   |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
insert into employee values(1,'汪飞','男','13700102535'); #成功
mysql> select * from employee;
+-----+-------+--------+-------------+
| eid | ename | gender | tel         |
+-----+-------+--------+-------------+
|   1 | 汪飞  || 13700102535 |
+-----+-------+--------+-------------+
1 row in set (0.00 sec)insert into employee(eid,ename) values(2,'天琪'); #成功
mysql> select * from employee;
+-----+-------+--------+-------------+
| eid | ename | gender | tel         |
+-----+-------+--------+-------------+
|   1 | 汪飞  || 13700102535 |
|   2 | 天琪  ||             |
+-----+-------+--------+-------------+
2 rows in set (0.00 sec)
insert into employee(eid,ename) values(3,'二虎');
#ERROR 1062 (23000): Duplicate entry '' for key 'tel'  
#如果tel有唯一性约束的话会报错,如果tel没有唯一性约束,可以添加成功

(2)建表后

alter table 表名称 modify 字段名 数据类型 default 默认值;#如果这个字段原来有非空约束,你还保留非空约束,那么在加默认值约束时,还得保留非空约束,否则非空约束就被删除了
#同理,在给某个字段加非空约束也一样,如果这个字段原来有默认值约束,你想保留,也要在modify语句中保留默认值约束,否则就删除了
alter table 表名称 modify 字段名 数据类型 default 默认值 not null;
create table employee(eid int primary key,ename varchar(20),gender char,tel char(11) not null
);
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | NULL    |       |
| tel    | char(11)    | NO   |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
alter table employee modify gender char default '男';  #给gender字段增加默认值约束
alter table employee modify tel char(11) default ''; #给tel字段增加默认值约束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     ||       |
| tel    | char(11)    | YES  |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)
alter table employee modify tel char(11) default ''  not null;#给tel字段增加默认值约束,并保留非空约束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     ||       |
| tel    | char(11)    | NO   |     |         |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

8.4如何删除默认值约束

alter table 表名称 modify 字段名 数据类型 ;#删除默认值约束,也不保留非空约束alter table 表名称 modify 字段名 数据类型  not null; #删除默认值约束,保留非空约束
alter table employee modify gender char; #删除gender字段默认值约束,如果有非空约束,也一并删除
alter table employee modify tel char(11)  not null;#删除tel字段默认值约束,保留非空约束
mysql> desc employee;
+--------+-------------+------+-----+---------+-------+
| Field  | Type        | Null | Key | Default | Extra |
+--------+-------------+------+-----+---------+-------+
| eid    | int(11)     | NO   | PRI | NULL    |       |
| ename  | varchar(20) | YES  |     | NULL    |       |
| gender | char(1)     | YES  |     | NULL    |       |
| tel    | char(11)    | NO   |     | NULL    |       |
+--------+-------------+------+-----+---------+-------+
4 rows in set (0.00 sec)

9.面试

面试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支持多种存储引擎,每一个表都可以指定一个不同的存储引擎,需要注意的是:外键约束是用来保证数据的参照完整性的,如果表之间需要关联外键,却指定了不同的存储引擎,那么这些表之间是不能创建外键约束的。所以说,存储引擎的选择也不完全是随意的。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/240622.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

鸿蒙开发者工具安装及入门程序

下载工具DevEco Studio IDE 官网下载&#xff1a;HUAWEI DevEco Studio和SDK下载和升级 | HarmonyOS开发者 开发工具的安装 解压下载好的压缩包&#xff0c;一路无脑安装即可&#xff0c;安装完的使用方法类似于IDEA、WebStorm的使用&#xff0c;快捷键一致&#xff0c;默认黑…

【笔记】Spring的循环依赖

Spring的循环依赖 ObjectFactory:函数式接口&#xff0c;可以将lambda表达式作为参数放在方法的实参种&#xff0c;在方法执行的时候&#xff0c;并不会实际的调用当前lambda表达式&#xff0c;只有在调用getObject方法的时候才回去调用lambda表达式 为什么spring要用三级缓存…

常用的百兆网络变压器与RJ45网口的参考连接电路有哪些,主要注意事项在哪里呢?

Hqst华轩盛(石门盈盛)电子导读&#xff1a;一起来了解常用的百兆网络变压器与RJ45网口的参考连接电路有哪些&#xff0c;主要注意事项在哪里呢&#xff1f; 第一,常用的百兆网络变压器与RJ45网口的参考连接电路 常用百兆网络变压器与网口连接器分开为独立电子元件的分离式参考电…

TrustZone之与非安全虚拟化交互

到目前为止&#xff0c;我们在示例中忽略了非安全状态中可能存在的虚拟化程序。当存在虚拟化程序时&#xff0c;虚拟机与安全状态之间的许多通信将通过虚拟化程序进行。 例如&#xff0c;在虚拟化环境中&#xff0c;SMC用于访问固件功能和可信服务。固件功能包括诸如电源管理之…

Ubuntu 常用命令之 top 命令用法介绍

&#x1f4d1;Linux/Ubuntu 常用命令归类整理 top命令是Linux下常用的性能分析工具&#xff0c;可以实时动态地查看系统中各个进程的资源占用状况&#xff0c;类似于Windows的任务管理器。它可以显示系统总的和分区的CPU使用率、内存使用率、交换区使用率、系统负载、进程数、…

MFC静态链接+libtiff静态链接提示LNK2005和LNK4098

编译报错 1>msvcrt.lib(ti_inst.obj) : error LNK2005: "private: __thiscall type_info::type_info(class type_info const &)" (??0type_infoAAEABV0Z) 已经在 libcmtd.lib(typinfo.obj) 中定义 1>msvcrt.lib(ti_inst.obj) : error LNK2005: "pr…

BUUCTF-Linux Labs

Linux Labs 根据题目给出的内容&#xff0c;在kali中连接靶机&#xff0c;输入密码进入命令行模式 ls发现什么都没有&#xff0c;有可能进入到了一个空文件夹 cd .. 切换到上一层目录&#xff0c;ls查看此目录下的内容&#xff0c;发现flag.txt文件&#xff0c;查看文件是flag …

超维空间S2无人机使用说明书——32、使用yolov7进行目标识别

引言&#xff1a;为了提高yolo识别的质量&#xff0c;提高了yolo的版本&#xff0c;改用yolov7进行物体识别&#xff0c;同时系统兼容了低版本的yolo&#xff0c;包括基于C的yolov3和yolov4&#xff0c;也有更高版本的yolov8。 简介&#xff0c;为了提高识别速度&#xff0c;系…

w15初识php基础

一、计算100之内的偶数之和 实现思路 所有的偶数除2都为0 代码实现 <?php # 记录100以内的偶数和 $number1; $num0; while($number<100){if($number%20){ $num$number;}$number1; } echo $num; ?>输出的结果 二、计算100之内的奇数之和 实现思路 所有的奇数除…

HTML+CSS做一个时尚柿子造型计时器

文章目录 💕效果展示💕代码展示HTMLJS💕效果展示 💕代码展示 HTML <!DOCTYPE html> <html lang

使用低代码工具构建电商平台:简化开发流程,加速应用搭建

在数字化时代&#xff0c;电商平台成为了各类企业的重要组成部分。然而&#xff0c;传统的软件开发过程往往漫长而复杂&#xff0c;需要大量的编码和调试工作。随着低代码工具的出现&#xff0c;开发者可以通过简化的方式来搭建电商平台应用&#xff0c;从而更快速地满足业务需…

surface pro重置win10后没微软账号如何登录

Surface pro官方镜像恢复详细图文步骤-CSDN博客 如果不懂重置系统请看上面的链接 win10-win11都开始默认要求输入微软账号才能使用。但依然有入口可以给没微软账号的用户使用的 第一步&#xff0c;重置后会要求连互联网&#xff0c;这一步要自己找个网络连接上&#xff0c;不…

十大经典排序算法(个人总结C语言版)

文章目录 一、前言二、对比1.排序算法相关概念1.1 时间复杂度1.2 空间复杂度1.3 排序方式1.4 稳定度 2.表格比较3.算法推荐3.1 小规模数据3.2 中等规模数据3.3 大规模数据3.4 特殊需求 三、排序算法1.冒泡排序&#xff08;Bubble Sort&#xff09;1.1 简介1.2 示例代码&#xf…

智能酒精壁炉在户外装饰中展现的独特魅力

智能酒精壁炉&#xff0c;一种独特的户外装饰和实用性产品&#xff0c;以其独有的魅力在户外场景中迅速赢得了人们的喜爱和欢迎。 在露营时&#xff0c;智能酒精壁炉由于便携性&#xff0c;可以很轻松地携带到露营地点。并且无需外接电源或气体&#xff0c;为露营者提供了简单而…

swing快速入门(二十五)

注释很详细&#xff0c;直接上代码 新增内容 1.ImageIO.write读取并显示图片 2.ImageIO.writeImageIO.write读取并保存图片 package swing21_30;import javax.imageio.ImageIO; import java.awt.*; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent…

使用web_video_server进行网页段的视频传输

引言&#xff1a;在项目中&#xff0c;需要实现无人机摄像头采集到的图像回传到window下进行查看&#xff0c;为此&#xff0c;选择使用web_video_server功能包实现局域网下的图像传输 硬件环境&#xff1a; 硬件&#xff1a;Jetson orin nano 8G D435摄像头 环境&#xff…

电子病历编辑器源码,提供电子病历在线制作、管理和使用的一体化电子病历解决方案

概述&#xff1a; 电子病历是指医务人员在医疗活动过程中,使用医疗机构信息系统生成的文字、符号、图表、图形、数据、影像等数字化信息,并能实现存储、管理、传输和重现的医疗记录,是病历的一种记录形式。 医院通过电子病历以电子化方式记录患者就诊的信息&#xff0c;包括&…

2024年pmp考试还有多久啊?怎么备考?

一般来说每年3、6、9、12月考试&#xff0c;一年四次&#xff0c;具体时间以官网通知为准。报考时间提前2个月报名&#xff0c;2023年的最后一次考试时间是11月&#xff0c;已经截止报名了。所以下一次考试就得等到2024年3月了。 想知道怎么备考先来分析一下现在的“新”考纲&…

进程同步与进程互斥-第二十四天

目录 前言 什么是进程同步 什么是进程互斥 四大区 遵循原则 本节思维导图 前言 进程具有异步性&#xff0c;异步性是指&#xff0c;各并发执行的进程以各自独立的、不可预知的速度向前推进&#xff0c;因此为了让进程以我们想要的顺序执行&#xff0c;操作系统引入了“进…

概率中的50个具有挑战性的问题[03/50]:轻率的陪审员

一、说明 我最近对与概率有关的问题产生了兴趣。我偶然读到了弗雷德里克莫斯特勒&#xff08;Frederick Mosteller&#xff09;的《概率论中的五十个具有挑战性的问题与解决方案》&#xff08;Fifty Challenge Problems in Probability with Solutions&#xff09;一书。我认为…