自增列 AUTO_INCREMENT
1. 作用:某个字段的值自增
2. 特点
- 一个表最多只能有一个自增长列
- 当需要产生唯一标识符或顺序值时,可设置自增长
- 自增长列约束的列必须是键列(主键列,唯一键列)
- 自增约束的列的数据类型必须是整数类型
- 如果自增列指定了 0 和 null,会在当前最大值的基础上自增;如果自增列手动指定了具体值,直接赋值为具体值
3. 添加自增约束
- 建表时添加
# 语法
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)
)
- 建表后添加
# 语法
alter table 表名称 modify 字段名 数据类型 auto_increment;
# 示例
alter table employee modify eid int auto_increment;
4. 删除自增约束
# 语法
alter table 表名称 modify 字段名 数据类型; #去掉auto_increment相当于删除
# 示例
alter table employee modify eid int;
5. MySQL 8.0新特性—自增变量的持久化
- 在MySQL 8.0之前,自增主键AUTO_INCREMENT的值如果大于max(primary key)+1,在MySQL重启后,会重置AUTO_INCREMENT=max(primary key)+1,这种现象在某些情况下会导致业务主键冲突或者其他难以发现的问题
- MySQL 8.0将自增主键的计数器持久化到重做日志中。每次计数器发生改变,都会将其写入重做日志中。如果数据库重启,InnoDB会根据重做日志中的信息来初始化计数器的内存值
FOREIGN KEY 约束
1. 作用:限定某个表的某个字段的引用完整性
2. 主表和从表/父表和子表
- 主表(父表):被引用的表,被参考的表
- 从表(子表):引用别人的表,参考别人的表
3. 特点
- 从表的外键列,必须引用/参考主表的主键或唯一约束的列,因为被依赖/被参考的值必须是唯一的
- 在创建外键约束时,如果不给外键约束命名,默认名不是列名,而是自动产生一个外键名(例如student_ibfk_1;),也可以指定外键约束名。
- 创建(CREATE)表时就指定外键约束的话,先创建主表,再创建从表
- 删表时,先删从表(或先删除外键约束),再删除主表
- 当主表的记录被从表参照时,主表的记录将不允许删除,如果要删除数据,需要先删除从表中依赖该记录的数据,然后才可以删除主表的数据
- 在“从表”中指定外键约束,并且一个表可以建立多个外键约束
- 从表的外键列与主表被参照的列名字可以不相同,但是数据类型必须一样,逻辑意义一致。如果类型不一样,创建子表时,就会出现错误“ERROR 1005 (HY000): Can't create
table'database.tablename'(errno: 150)”。例如:都是表示部门编号,都是int类型。 - 当创建外键约束时,系统默认会在所在的列上建立对应的普通索引。但是索引名是外键的约束
名。(根据外键查询效率很高) - 删除外键约束后,必须 手动 删除对应的索引
4. 添加外键约束
- 建表时添加
# 语法
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的数据类型一致,意义都是表示部门的编号
);
- 建表后添加
# 语法
ALTER TABLE 从表名 ADD
[CONSTRAINT 约束名] FOREIGN KEY (从表的字段) REFERENCES 主表名(被引用字段)
-- 设置约束等级
[on update xx][on delete xx];
# 示例
ALTER TABLE emp1
ADD [CONSTRAINT emp_dept_id_fk] FOREIGN KEY(dept_id) REFERENCES dept(dept_id);
5. 约束关系是针对双方的
- 添加了外键约束后,主表的修改和删除数据受约束
- 添加了外键约束后,从表的添加和修改数据受约束
- 在从表上建立外键,要求主表必须存在
- 删除主表时,要求从表先删除,或将从表中外键引用该主表的关系先删除
6. 约束等级
- Cascade方式 :在父表上update/delete记录时,同步update/delete掉子表的匹配记录
- Set null方式 :在父表上update/delete记录时,将子表上匹配记录的列设为null,但是要注意子表的外键列不能为not null
- No action方式 :如果子表中有匹配的记录,则不允许对父表对应候选键进行update/delete操作
- Restrict方式 :同no action, 都是立即检查外键约束,默认的等级相当于Restrict
- Set default方式 (在可视化工具SQLyog中可能显示空白):父表有变更时,子表将外键列设置成一个默认的值,但Innodb不能识别
7. 删除外键约束
# 第一步先查看约束名和删除外键约束
SELECT * FROM information_schema.table_constraints WHERE table_name = '表名称';
ALTER TABLE 从表名 DROP FOREIGN KEY 外键约束名;
# 第二步查看索引名和删除索引。(注意,只能手动删除)
SHOW INDEX FROM 表名称;
ALTER TABLE 从表名 DROP INDEX 索引名;
8. 外键使用注意
- 在 MySQL 里,外键约束是有成本的,需要消耗系统资源。
- 对于大并发的 SQL 操作,有可能会不适合。比如大型网站的中央数据库,可能会因为外键约束的系统开销而变得非常慢 。所以,MySQL 允许你不使用系统自带的外键约束,在应用层面 完成检查数据一致性的逻辑。也就是说,即使你不用外键约束,也要想办法通过应用层面的附加逻辑,来实现外键约束的功能,确保数据的一致性
- 外键与级联更新适用于 单机低并发 ,不适合 分布式 、 高并发集群 ;级联更新是强阻塞,存在数据库 更新风暴 的风险;外键影响数据库的插入速度
CHECK 约束
1. 作用:检查某个字段的值是否符合xx要求,一般指的是值的范围
2. 添加约束
- MySQL5.7 可以使用check约束,但check约束对数据验证没有任何作用
- 但是MySQL 8.0中可以使用check约束了
create table employee(
eid int primary key,
ename varchar(5),
gender char check ('男' or '女')
);
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)
DEFAULT 约束
1. 作用:
- 给某个字段/某列指定默认值
- 一旦设置默认值,在插入数据时,如果此字段没有显式赋值,则赋值为默认值
2. 添加默认值约束
- 建表时添加
# 语法:默认值约束一般不在唯一键和主键列上加
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 '' #默认是空字符串
);
CREATE TABLE myemp(
id INT AUTO_INCREMENT PRIMARY KEY,
NAME VARCHAR(15),
salary DOUBLE(10,2) DEFAULT 2000
);
- 建表后添加
- 如果这个字段原来有非空约束,那么在加默认值约束时,还得保留非空约束,否则非空约束就被删除了
- 同理,在给某个字段加非空约束也一样,如果这个字段原来有默认值约束,你想保留,也要在modify语句中保留默认值约束,否则就删除了
# 语法
alter table 表名称 modify 字段名 数据类型 default 默认值;
# 示例
alter table employee modify gender char default '男'; #给gender字段增加默认值约束
alter table employee modify tel char(11) default ''; #给tel字段增加默认值约束
# 给tel字段增加默认值约束,并保留非空约束
alter table employee modify tel char(11) default '' not null;
3. 删除默认值约束
# 删除默认值约束,也不保留非空约束
alter table 表名称 modify 字段名 数据类型 ;
# 删除默认值约束,保留非空约束
alter table 表名称 modify 字段名 数据类型 not null;
# 删除gender字段默认值约束,如果有非空约束,也一并删除
alter table employee modify gender char;
# 删除tel字段默认值约束,保留非空约束
alter table employee modify tel char(11) not null;
约束的常见问题
1. 为什么不想要 null 的值?
- 不好比较。null是一种特殊值,比较时只能用专门的is null 和 is not null来比较。碰到运算符,通常返回null。
- 效率不高。影响提高索引效果。因此,我们往往在建表时 not null default '' 或 default 0
2. 每个表都可以任意选择存储引擎?
- MySQL支持多种存储引擎,每一个表都可以指定一个不同的存储引擎
- 注意:外键约束是用来保证数据的参照完整性的,如果表之间需要关联外键,却指定了不同的存储引擎,那么这些表之间是不能创建外键约束的