Mysql之约束下篇

Mysql之约束下篇

  • 自增列(AUTO_INCREMENT)
    • 关键字
    • 特点和要求
    • 添加自增约束
    • 删除自增约束
    • Mysql8.0新特性-自增变量的持久化
    • FOREIGN KEY 约束
      • 关键字
      • 主表和从表/父表和子表
      • 特点
      • 添加外键约束
      • 约束等级
      • 删除外键约束
      • 面试问题
      • DEFAULT约束
        • 作用
        • 关键字
        • 添加默认值约束
        • 删除默认值约束
        • CHECK约束
          • 作用
          • 关键字
          • 案例
          • 面试问题

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