MySQL六种束缚的示例详解(全网最全)
一、概述
概念: 束缚是作用于表中字段上的规则,用于限制存储在表中的数据。
目的: 保证数据库中数据的正确、有效性和完全性。
分类:
注意:束缚是作用于表中字段上的,可以在创建表/修改表的时候添加束缚。
二、束缚演示
上面我们介绍了数据库中常见的束缚,和束缚触及到的关键字,那这些束缚我们到底怎样在创建表、修改表的时候来指定呢,接下来我们就通过一个案例,来演示一下。
案例需求: 根据需求,完成表结构的创建。需求以下:
对应的建表语句为:
id INT AUTO_INCREMENT PRIMARY KEY COMMENT ‘ID唯一标识’,
NAME VARCHAR ( 10 ) NOT NULL UNIQUE COMMENT ‘姓名’,
age INT CHECK ( age > 0 && age <= 120 ) COMMENT ‘年龄’,
STATUS CHAR ( 1 ) DEFAULT ‘1’ COMMENT ‘状态’,
gender CHAR ( 1 ) COMMENT ‘性别’
);
在为字段添加束缚时,我们只需要在字段以后加上束缚的关键字便可,需要关注其语法。
我们履行上面的SQL把表结构创建完成,然后接下来,就能够通过一组数据进行测试,从而验证一下,束缚会不会可以生效。
(1)先是新增了三条数据
insert into tb_user(name,age,status,gender) values (‘Tom3′,19,’1′,’男’);
新增三条数据,居然用了21秒,这是甚么情况?
本来我还以为是新增这些束缚致使新增数据慢的,其实不是,由于我这个是阿里的linux服务器,然后我在linux中通过客户端连接mysql履行新增,也就0.01秒,说明这是navicat连接远程主机耗时的。
就算新增了这些束缚,会致使新增数据慢,那也是批量的时候才能明显发觉出来,单条数据基本上看不出来的。
(2)测试name NOT NULL
(3)测试name UNIQUE(唯一)
上面新增的数据已有Tom3了,再次新增直接报错。
虽然报错了,但是我们这时候候再新增一条数据会发现一个现象。
明明是自增id,但是却没有4,缘由就是UNIQUE(唯一)是在申请完自增id后,准备入库了,然后这时候候会先去看看库里面会不会有存在相同name的值,如果有则新增失败,虽然新增失败了,但是自增id已申请过了!
相反我们刚刚测试的null的name的时候他并没有去申请id,由于他在刚开始就已判断他为空了,还没走到申请id这一步。
判断会不会为空 -》 申请自增id -》 判断会不会已有存在的值
总结:当新增的name不为空的时候,但是和之前存在的数据有相同的,这时候候新增会失败,但是他会申请主键id。
(4)测试CHECK
我们设置的是age一定要大于0小于等于120,否则保存失败!
insert into tb_user(name,age,status,gender) values (‘Tom5′,121,’1′,’男’);
(5)测试 DEFAULT ‘1’ 默许值
(6)上面,我们是通过编写SQL语句的情势来完成束缚的指定,那假设我们是Navicat客户端呢?
主键自增
name唯一束缚
status默许为1
三、外键束缚
1、 甚么是外键束缚
外键: 用来让两张表的数据之间建立连接,从而保证数据的一致性和完全性。
我们来看一个例子:
左边的emp表是员工表,里面存储员工的基本信息,包括员工的ID、姓名、年龄、职位、薪资、入职日期、上级主管ID、部门ID,在员工的信息中存储的是部门的ID dept_id,而这个部门的ID是关联的部门表dept的主键id,那emp表的dept_id就是外键,关联的是另外一张表的主键。
2、 不使用外键有甚么影响
通过上面的示例,我们分别来演示 添加外键 和不添加外键的区分,首先来看不添加 外键 对数据有甚么影响:
准备数据:
INSERT INTO dept (id, name) VALUES (1, ‘研发部’), (2, ‘市场部’),(3, ‘财务部’), (4, ‘销售部’), (5, ‘总经办’);
CREATE TABLE emp (
id INT auto_increment COMMENT ‘ID’ PRIMARY KEY,
NAME VARCHAR ( 50 ) NOT NULL COMMENT ‘姓名’,
age INT COMMENT ‘年龄’,
job VARCHAR ( 20 ) COMMENT ‘职位’,
salary INT COMMENT ‘薪资’,
entrydate date COMMENT ‘入职时间’,
managerid INT COMMENT ‘直属领导ID’,
dept_id INT COMMENT ‘部门ID’
) COMMENT ‘员工表’;
INSERT INTO emp (id, name, age, job,salary, entrydate, managerid, dept_id) VALUES
(1, ‘金庸’, 66, ‘总裁’,20000, ‘2000-01-01’, null,5),
(2, ‘张无忌’, 20, ‘项目经理’,12500, ‘2005⑴2-05’, 1,1),
(3, ‘杨逍’, 33, ‘开发’, 8400,’2000⑴1-03′, 2,1),
(4, ‘韦一笑’, 48, ‘开 发’,11000, ‘2002-02-05’, 2,1),
(5, ‘常遇春’, 43, ‘开发’,10500, ‘2004-09-07’, 3,1),
(6, ‘小昭’, 19, ‘程 序员鼓励师’,6600, ‘2004⑴0⑴2’, 2,1);
接下来,我们可以做一个测试,删除id为1的部门信息。
结果,我们看到删除成功,而删除成功以后,部门表不存在id为1的部门,而在emp表中还有很多的员工,关联的为id为1的部门,此时就出现了数据的不完全性。 而要想解决这个问题就得通过数据库的外键束缚。
正常开发当中有时候会通过业务代码来控制数据的不完全性,例如删除部门的时候会先根据部门id去查看一下有无对应的员工表,如果有则删除失败,没有则删除成功。
3、 添加外键的语法
可以在创建表的时候直接添加外键,也能够对现已存在的表添加外键。
(1)方式一
字段名 数据类型,
…
[CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名)
);
使用示例:
id INT auto_increment COMMENT ‘ID’ PRIMARY KEY,
NAME VARCHAR ( 50 ) NOT NULL COMMENT ‘姓名’,
age INT COMMENT ‘年龄’,
job VARCHAR ( 20 ) COMMENT ‘职位’,
salary INT COMMENT ‘薪资’,
entrydate date COMMENT ‘入职时间’,
managerid INT COMMENT ‘直属领导ID’,
dept_id INT COMMENT ‘部门ID’,
CONSTRAINT fk_emp_dept_id FOREIGN KEY (dept_id) REFERENCES dept (id)
) COMMENT ‘员工表’;
也能够省略掉CONSTRAINT fk_emp_dept_id
这样mysql就会自动给我们起外键名称。
方式二:对现存在的表添加外键
使用示例:
方式三:Navicat添加外键
删除外键:
使用示例:
4、 删除/更新行动
添加了外键以后,在删除父表数据时产生的束缚行动,我们就称为删除/更新行动。具体的删除/更新行动有以下几种:
在mysql8.0.27版本当中,RESTRICT是默许的删除更新行动!区别的版本可能也会有所差距!
具体语法为:
就是比本来添加外键后面多了这些ON UPDATE CASCADE ON DELETE CASCADE
,代表的是更新时采取CASCADE
,删除时也采取CASCADE
5、 演示删除/更新行动
(1)演示RESTRICT
当在父表中删除/更新对应记录时,首先检查该记录会不会有对应外键,如果有则不允许删除/更新。 (与 NO ACTION 一致) 默许行动
首先要添加外键,默许是RESTRICT行动!
当我要删除父表当中id为5的记录的时候会报错,缘由就是emp表的dept_id存在5。假设要更新id也一样会报错的!
(2)演示CASCADE
当在父表中删除/更新对应记录时,首先检查该记录会不会有对应外键,如果有,则
也删除/更新外键在子表中的记录。
删除外键的语法:
删除外键的示例:
指定外键的删除更新行动为cascade
修改父表id为1的记录,将id修改成6
我们发现,原来在子表中dept_id值为1的记录,现在也变成6了,这就是cascade级联的效果。
在一般的业务系统中,不会修改一张表的主键值。
删除父表id为6的记录
我们发现,父表的数据删除成功了,但是子表中关联的记录也被级联删除。
(3)演示SET NULL
当在父表中删除对应记录时,首先检查该记录会不会有对应外键,如果有则设置子表中该外键值为null(这就要求该外键允许取null)。
在进行测试之前,我们先需要删除上面建立的外键 fk_emp_dept_id。然后再通过数据脚本,将emp、dept表的数据恢复了。
接下来,我们删除id为1的数据,看看会产生甚么样的现象。
我们发现父表的记录是可以正常的删除的,父表的数据删除以后,再打开子表 emp,我们发现子表emp的dept_id字段,原来dept_id为1的数据,现在都被置为NULL了。
这就是SET NULL这类删除/更新行动的效果。
四、主键id到底用自增好或者uuid好
在mysql中设计表的时候,mysql官方推荐不要使用uuid或不连续不重复的雪花id(long形且唯一),而是推荐连续自增的主键id,官方的推荐是auto_increment,那末为何不建议采取uuid,使用uuid究竟有甚么坏处?
1、测试uuid和自增id还有随机数插入效力
首先来建立三张表,user_auto_key代表的是自增表,user_uuid代表的是id存储的uuid,random_key代表的是表id是雪花id。然后通过连接jdbc批量插入数据测试测试结果以下:
在已有数据量为130W的时候:我们再来测试一下插入10w数据,看看会有甚么结果:
可以看出在数据量100W左右的时候,uuid的插入效力垫底,并且在后序增加了130W的数据,uudi的时间又直线降落。时间占用量整体可以打出的效力排名为:auto_key>random_key>uuid
,uuid的效力最低
2、使用自增id的缺点
1.他人一旦爬取你的数据库,就能够根据数据库的自增id获得到你的业务增长信息,很容易分析出你的经营情况
2.对高并发的负载,innodb在按主键进行插入的时候会造成明显的锁争用,主键的上界会成为争抢的热门,由于所有的插入都产生在这里,并发插入会致使间隙锁竞争
3.Auto_Increment锁机制会造成自增锁的抢夺,有一定的性能损失
4.自增id触及到数据迁移的话是相当麻烦的!
5.而且一旦触及到分库分表自增id也是相当麻烦的!
3、使用uuid的缺点
由于uuid相对顺序的自增id来讲是毫无规律可言的,新行的值不一定要比之前的主键的值要大,所以innodb没法做到总是把新行插入到索引的最后,而是需要为新行寻觅新的适合的位置从而来分配新的空间。这个进程需要做很多额外的操作,数据的毫无顺序会致使数据散布散乱,将会致使以下的问题:
1.写入的目标页极可能已刷新到磁盘上并且从缓存上移除,或还没有被加载到缓存中,innodb在插入之前不能不先找到并从磁盘读取目标页到内存中,这将致使大量的随机IO
2.由于写入是乱序的,innodb不能不频繁的做页分裂操作,以便为新的行分配空间,页分裂致使移动大量的数据,一次插入最少需要修改三个页以上
3.由于频繁的页分裂,页会变得稀疏并被不规则的填充,终究会致使数据会有碎片
页分裂和碎片问题,uuid确切会引发这个问题,但雪花可以解决这个问题,雪花算法天然具有顺序性新插入的ID一定是最大的,所以我认为用雪花算法是一个很不错的选择!
五、实际开发尽可能少用外键
主键和索引是不可少的,不但可以优化数据检索速度,开发人员还省不其它的工作。
矛盾焦点:数据库设计会不会需要外键。这里有两个问题:
一个是如何保障数据库数据的完全性和一致性;
二是第一条对性能的影响。
这里分为了正方和反方两个观点,供参考!
1、正方观点
1.由数据库本身保证数据一致性,完全性,更可靠,由于程序很难100%保证数据的完全性,而用外键即便在数据库服务器当机或出现其他问题的时候,也能够最大限度的保证数据的一致性和完全性。
2.有主外键的数据库设计可以增加ER图的可读性,这点在数据库设计时非常重要。
3.外键在一定程度上说明的业务逻辑,会使设计周到具体全面。
数据库和利用是一对多的关系,A利用会保护他那部份数据的完全性,系统一变大时,增加了B利用,A和B两个利用或许是区别的开发团队来做的。他们怎样调和保证数据的完全性,而且一年以后如果又增加了C利用呢?
2、反方观点
1.可以用触发器或利用程序保证数据的完全性
2.过分强调或说使用主键/外键会平增开发难度,致使表过量等问题
3.不用外键时数据管理简单,操作方便,性能高(导入导出等操作,在insert, update, delete 数据的时候更快)
在海量的数据库中想都不要去想外键,试想,一个程序每天要insert数百万条记录,当存在外键束缚的时候,每次要去扫描此记录会不会合格,一般还不 止一个字段有外键,这样扫描的数量是成级数的增长!我的一个程序入库在3个小时做完,如果加上外键,需要28个小时!
3、结论
1.在大型系统中(性能要求不高,安全要求高),使用外键;在大型系统中(性能要求高,安全自己控制),不用外键;小系统随意,最好用外键。
2.用外键要适当,不能过分寻求
3.不用外键而用程序控制数据一致性和完全性时,应当写一层来保证,然后个个利用通过这个层来访问数据库。
需要注意的是:
MySQL允许使用外键,但是为了完全性检验的目的,在除InnoDB表类型以外的所有表类型中都疏忽了这个功能。这可能有些奇异,实际上却非常正常:对数据库的所有外键的每次插入、更新和删除后,进行完全性检查是一个耗费时间和资源的进程,它可能影响性能,特别是当处理复杂的或是缠绕的连接数时。因此,用户可以在表的基础上,选择合适于特定需求的。
所以,如果需要更好的性能,并且不需要完全性检查,可以选择使用MyISAM表类型,如果想要在MySQL中根据参照完全性来建立表并且希望在此基础上保持良好的性能,最好选择表结构为innoDB类型
本篇文章到此结束,如果您有相关技术方面疑问可以联系我们技术人员远程解决,感谢大家支持本站!
文章来源:丸子建站
文章标题:MySQL六种束缚的示例详解(全网最全)
https://www.wanzijz.com/view/62719.html