• MySQL:表的约束



    全文约 5725 字,预计阅读时长: 17分钟


    表的约束

    真正约束字段的是数据类型,但是数据类型约束很单一,需要有一些额外的约束,更好的保证数据的合法性,从业务逻辑角度保证数据的正确性。比如有一个字段是email,要求是唯一的。

    表的约束很多,这里主要介绍如下几个: null/not null,default, comment, zerofillprimary keyauto_incrementunique key


    空属性

    • 两个值:null(默认的)和not null(不为空)。
    • 数据库默认字段基本都是字段为空,但是实际开发时,尽可能保证字段不为空,因为数据为空没办法参与运算。
    # mysql> select null;
    +------+
    | NULL |
    +------+
    | NULL |
    +------+
    1 row in set (0.00 sec)
    
    # mysql> select 1+null;
    +--------+
    | 1+null |
    +--------+
    | NULL |
    +--------+
    1 row in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    案例:创建一个班级表,包含班级名和班级所在的教室。

    • 站在正常的业务逻辑中:
      • 如果班级没有名字,你不知道你在哪个班级
      • 如果教室名字可以为空,就不知道在哪上课
    • 所以我们在设计数据库表的时候,一定要在表中进行限制,满足上面条件的数据就不能插入到表中。这就是“约束”。
    # mysql> create table myclass(
    -> class_name varchar(20) not null,
    -> class_room varchar(10) not null);
    Query OK, 0 rows affected (0.02 sec)
    
    # mysql> desc myclass;
    
    //插入数据时,没有给教室数据插入失败:
    # mysql> insert into myclass(class_name) values('class1');
    ERROR 1364 (HY000): Field 'class_room' doesn't have a default value
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    在这里插入图片描述


    默认值

    • 默认值:某一种数据会经常性的出现某个具体的值,可以在一开始就指定好,在需要真实数据的时候,用户可以选择性的使用默认值。
    • 一个属性列,不为空和默认值的使用二选一。虽然默认值的优先比不为空高。
    # mysql> create table tt10 (
    -> name varchar(20) not null,
    -> age tinyint unsigned default 0,
    -> sex char(2) default '男'
    -> );
    Query OK, 0 rows affected (0.00 sec)
    
    # mysql> desc tt10;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    在这里插入图片描述

    • 默认值的生效:数据在插入的时候不给该字段赋值,就使用默认值。需要指明给其他的那个字段赋值。只有设置了default的列,才可以在插入值的时候,对列进行省略。
    # mysql> insert into tt10(name) values('zhangsan');
    Query OK, 1 row affected (0.00 sec)
    
    • 1
    • 2

    列描述

    • 列描述:comment,没有实际含义,专门用来描述字段,会根据表创建语句保存,用来给程序员或DBA来进行了解,相当于语言中的注释。一般写在字段的最后。
    # mysql> create table tt12 (
    -> name varchar(20) not null comment '姓名',
    -> age tinyint unsigned default 0 comment '年龄',
    -> sex char(2) default '男' comment '性别'
    -> );
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 通过desc查看不到注释信息:通过show可以看到:
    # mysql> show create table tt12\G
    *************************** 1. row ***************************
    Table: tt12
    Create Table: CREATE TABLE `tt12` (
    `name` varchar(20) NOT NULL COMMENT '姓名',
    `age` tinyint(3) unsigned DEFAULT '0' COMMENT '年龄',
    `sex` char(2) DEFAULT '男' COMMENT '性别'
    ) ENGINE=MyISAM DEFAULT CHARSET=gbk
    1 row in set (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    zerofill

    • 刚开始学习数据库时,很多人对数字类型后面的长度很迷茫。只是设置了zerofill属性后的一种格式化输出位宽而已,不够用0填充,超过这个属性值也不影响。就像语言中的左对齐,右对齐一样。
    # mysql> alter table tt3 change a a int(5) unsigned zerofill;
    
    # mysql> show create table tt3\G
    *************************** 1. row ***************************
    Table: tt3
    Create Table: CREATE TABLE `tt3` (
    `a` int(5) unsigned zerofill DEFAULT NULL, --具有了zerofill
    `b` int(10) unsigned DEFAULT NULL
    ) ENGINE=MyISAM DEFAULT CHARSET=gbk
    1 row in set (0.00 sec)
    
    # mysql> select * from tt3;
    +-------+------+
    | a 	| b 	|
    +-------+------+
    | 00001 | 2 	|
    +-------+------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    主键

    • 主键:primary key用来唯一的约束该字段里面的数据,不能重复,不能为空,一张表中最多只能有一个主键;主键所在的列通常是整数类型。

    案例:创建表的时候直接在字段上指定主键。

    # mysql> create table tt13 (
    -> id int unsigned primary key comment '学号不能为空',
    -> name varchar(20) not null);
    Query OK, 0 rows affected (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4

    在这里插入图片描述

    • 主键约束:主键对应的字段中不能重复,一旦重复,操作失败。
    # mysql> insert into tt13 values(1, 'aaa');
    Query OK, 1 row affected (0.00 sec)
    
    • 1
    • 2
    • 当表创建好以后但是没有主键的时候,可以再次追加主键。
    # alter table 表名 add primary key(字段列表)
    
    • 1
    • 删除主键
    # alter table 表名 drop primary key;
    
    • 1

    复合主键

    • 在创建表的时候,在所有字段之后,使用primary key(主键字段列表)来创建主键,如果有多个字段作为主键,可以使用复合主键。只有当多个字段同时一样时,才算冲突。
    • 平时用的少。
    # mysql> create table tt14(
    -> id int unsigned,
    -> course char(10) comment '课程代码',
    -> score tinyint unsigned default 60 comment '成绩',
    -> primary key(id, course)// -- id和course为复合主键
    -> );
    
    # mysql> insert into tt14 (id,course)values(1, '123');
    ERROR 1062 (23000): Duplicate entry '1-123' for key 'PRIMARY' //-- 主键冲突
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    在这里插入图片描述


    自增长

    • auto_increment:当对应的字段,不给值,会自动的被系统触发,系统会从当前字段中已经有的最大值+1操作,得到一个新的不同的值。通常就是主键,也叫做逻辑主键。
    • 自增长的特点:
      • 任何一个字段要做自增长,前提是本身是一个索引(key一栏有值)
      • 自增长字段必须是整数
      • 一张表最多只能有一个自增长
    # mysql> create table tt21(
    -> id int unsigned primary key auto_increment,
    -> name varchar(10) not null default ''
    -> );
    
    # mysql> insert into tt21(name) values('a');
    # mysql> insert into tt21(name) values('b');
    
    # mysql> select * from tt21;
    +----+------+
    | id | name |
    +----+------+
    | 1 | a |
    | 2 | b |
    +----+------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 在插入后获取上次插入的 AUTO_INCREMENT 的值(批量插入获取的是第一个值),往中间插入不会自增长。
    # mysql > select last_insert_id();
    +------------------+
    | last_insert_id() |
    +------------------+
    | 1 |
    +------------------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    在这里插入图片描述


    唯一键

    • 一张表中有往往有很多字段需要唯一性,数据不能重复,但是一张表中只能有一个主键:唯一键就可以解决表中有多个字段需要唯一性约束的问题。
    • 主键对外,唯一键对内的多个列做约束,做约束的列的值不能相同
    # mysql> create table student (
    -> id char(10) unique comment '学号,不能重复,但可以为空',
    -> name varchar(10)
    -> );
    Query OK, 0 rows affected (0.01 sec)
    
    # mysql> insert into student(id, name) values('01', 'aaa');
    Query OK, 1 row affected (0.00 sec)
    
    # mysql> insert into student(id, name) values('01', 'bbb'); //--唯一约束不能重复
    ERROR 1062 (23000): Duplicate entry '01' for key 'id'
    
    # mysql> insert into student(id, name) values(null, 'bbb'); //-- 但可以为空
    Query OK, 1 row affected (0.00 sec)
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述


    外键

    • 外键用于定义主表和从表之间的关系:外键约束主要定义在从表上,主表则必须是有主键约束或unique约束。
    • 当定义外键后,要求外键列数据必须在主表的主键列存在或为null。
    • 语义上的普通外键;外键约束。
    //语法:
    # foreign key (字段名) references 主表()
    
    • 1
    • 2

    普通外键

    • 先创建主键表,再创建从表
      在这里插入图片描述
    mysql> select * from tt7,tt6 where tt7.cls_id = tt6.cls_id;
    +--------+----------+--------+--------+----------+
    | stu_id | stu_name | cls_id | cls_id | cls_name |
    +--------+----------+--------+--------+----------+
    |    666 | 小乔     |      2 |      2 | Python   |
    |    777 | 小朱     |      1 |      1 | C++      |
    +--------+----------+--------+--------+----------+
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 此时虽然两个表建立了联系,但可以插入一个学生不属于1班,2班的学生。还可以删除主表中的相关记录。没有约束性。

    外键约束

    • 先创建主键表,再创建从表,正常插入数据
    • 插入一个班级号为30的学生,因为没有这个班级,所以插入不成功
    • 插入班级id可以为null,比如来了一个学生,目前还没有分配班级。
    # create table myclass (
    	id int primary key,
    	name varchar(30) not null comment'班级名'
    	);
    
    # create table stu (
    	id int primary key,
    	name varchar(30) not null comment '学生名',
    	class_id int,
    	foreign key (class_id) references myclass(id)
    	);
    
    # mysql> insert into myclass values(10, 'C++大牛班'),(20, 'java大神班');//正常插入
    Query OK, 2 rows affected (0.03 sec)
    Records: 2 Duplicates: 0 Warnings: 0
    
    # mysql> insert into stu values(100, '张三', 10),(101, '李四',20);
    Query OK, 2 rows affected (0.01 sec)
    Records: 2 Duplicates: 0 Warnings: 0
    
    # mysql> insert into stu values(102, 'wangwu',30);//报错
    ERROR 1452 (23000): Cannot add or update a child row: a foreign key constraint fails (mytest.stu, CONSTRAINT stu_ibfk_1 FOREIGN KEY (class_id) REFERENCES myclass (id))
    
    # mysql> insert into stu values(102, 'wangwu', null);//可以为空
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    在这里插入图片描述

    如何理解外键约束

    • 首先我们承认,这个世界是数据很多都是相关性的。
    • 理论上,上面的例子,我们不创建外键约束,就正常建立学生表,以及班级表,该有的字段我们都有。
    • 此时,在实际使用的时候,可能会出现什么问题?
    • 有没有可能插入的学生信息中有具体的班级,但是该班级却没有在班级表中?比如只开了100班,101班,但是在上课的学生里面竟然有102班的学生(这个班目前并不存在),这很明显是有问题的。
    • 因为此时两张表在业务上是有相关性的,但是在业务上没有建立约束关系,那么就可能出现问题。
    • 解决方案就是通过外键完成的。建立外键的本质其实就是把相关性交给mysql去审核了,提前告诉mysql表之间的约束关系,那么当用户插入不符合业务逻辑的数据的时候,mysql不允许你插入。

    寄语

    • 建表时把该做的事情都做了。讨论一个具体事情时,有一个事情不明确,就必须把它弄明确。不然一般变更底层的数据库,上面的所有业务逻辑都要重做。
  • 相关阅读:
    JavaWeb 项目 --- 博客系统(前后分离)
    Nature Communications|柔性无感智能隐形眼镜(柔性传感/可穿戴电子/柔性电子)
    片内总线在cpu扮演什么角色?他为什么能实现高效,不同的CPU为什么采用不同的总线协议?
    带隙基准中运放相位裕度与增益裕度
    Spring系列12: `@Value` `@Resource` `@PostConstruct` `@PreDestroy` 详解
    栈和队列经典oj面试题
    Ubuntu中还换源 sudo apt-get update更新失败
    详细给你讲明白JVM发生CMS GC的 5 种情况
    redis相关文章汇总
    【OAuth2】十六、Spring Authorization Server如何生成并发放token的
  • 原文地址:https://blog.csdn.net/WTFamer/article/details/126697470