序言
这是很久以前刚开始学习MySql的笔记 ,所以会有些内容未完善,BBy过段时间复习数据库时在进行完善
终端开启数据库
- 开启服务器: net start MySQL80 #一定要在管理员权限下执行
- 关闭服务器: net stop MySQL80
- 登录MySQL: mysql -h 127.0.0.1 -uroot -pPassword
- 退出登录: exit
数据库基础知识
- 关系数据库是建立在关系模型上的,而关系模型本质上就是若干个存储数据的二维表,可以把它们看作很多Excel表。
- 表中的数据(除字段外每一行)称为记录。
- 表中的列称为字段,即属性。
- 数据中的NULL与C/C++语言中NULL不同,NULL表示字段数据不存在,即:一个整型字段如果为NULL不表示它的值为0,同样的,一个字符串型字段为NULL也不表示它的值为空串""。
- 通常情况下,字段应该避免允许为NULL。不允许为NULL可以简化查询条件,加快查询速度,也利于应用程序读取数据后无需判断是否为NULL。
命名规则
- MySQL 的命名规则同C/C++ 相似,是由字母、数字、下划线组成。但不同的是MySQL中不区分大小写(数据库名、表名、字段名均不区分大小写)。举个例子:数据库 time 和数据库 TIME 是同一个数据库。
创建数据库
create database db_name; # db_name 为数据库名
# 使用(进入)数据库
use db_name;
创建数据表
创建数据表单的格式:
CREATE TABLE <表名> ([表定义选项])[表选项][分区选项];
其中,[表定义选项]的格式为:
<列名1> <类型1> [,…] <列名n> <类型n>
CREATE TABLE:
<表名>:指定要创建表的名称,表名称可以被指定为 db_name.tbl_name,以便在特定的数据库中创建表。无论是否有当前数据库,都可以通过这种方式创建。在当前数据库中创建表时,可以省略 db-name。有些数据库可以使用加引号的识别名,例如,'mydb'.'mytbl' 是合法的,但 mysql 是不合法。
<表定义选项>:表创建定义,由列名(col_name)、列的定义(column_definition, 或者叫类型定义)以及可能的空值说明、完整性约束或表索引组成
# 方式一: 先使用表 ,然后在创建具体表单 table_name为表名
use database_name;
create table table_name( ... );
# 方式二 使用 数据库名.表名 不进入具体数据表,直接创建,也可以通过这中方式直接操作数据表
create table database_name.table_name( ... );
# 两种效果一样,都是在数据库database_name下创建一个为table_name的数据表
字符串类型 – varchar 和 char
-
CHAR类型的长度是固定的,在创建表时就指定了。其长度可以是0~255的任意值。例如,CHAR(100)就是指定CHAR类型的长度为100。CHAR 存储值时,它们会用空格右填充到指定的长度。
-
VARCHAR类型的长度是可变的,在创建表时指定了最大长度。定义时,其最大值可以取0~65535之间的任意值。指定VARCHAR类型的最大值以后,其长度可以在0到最大长度之间。例如,VARCHAR(100)的最大长度是100,但是不是每条记录都要占用100个字节,而是在这个最大值范围内使用多少就分配多少。VARCHAR类型实际占用的空间为字符串的实际长度加1或2,这样即可有效节约系统的空间。至于为什么为字符串实际长度加1或2,是因为在存储varchar类型的变量的时候,要在存储变量的前面将字符串的实际长度存储下来
-
实战建议
· 1、 char一定会使用指定的空间,varchar是根据数据来定空间
· 2、 char的数据查询效率比varchar高:varchar是需要通过后面的记录数来计算
· 3、 如果确定数据一定是占指定长度,那么使用char类型;
· 4、 如果不确定数据到底有多少,那么使用varchar类型;
· 5、 如果数据长度超过255个字符而在65535之内,直接使用varchar
· 6、 如果字符串尾部要保留空格,必须选择varchar
显示
- 显示所有数据库: show databases
- 显示所有数据表: show tables
- 显示数据表的创建结构: show create table table_name
- 显示数据表单结构: describe table_name (或则desc table_name)
- 查看数据表单中的记录: select * from table_name
数据的插入
-
# 插入完整的成员,无需在插入时指定字段 insert into table_name values('...','...',...); # 只指定插入成员的一部分属性 未指定的字段要求有默认值(未设置一班默认为NULL) insert into table_name (table_property1,table_property2...) values (property_value1,property_value2...);
删除
# 删除数据库: (删除数据库时 MySQL 不会确认,所以千万要 小心)
drop database database_name
# 删除数据表中的某一个条记录:
delete from table_name where table_property='value '
# 删除数据表单中的所有记录
delete from table_name where 1=1
enum 和 set
-
enum 枚举类型, 只取属性值集中的一个 若加了 NOT NULL 属性,则列表中的第一个将成为默认值
# 格式 属性名 enum('值1','值2',...,'值n') # 创建表单示例 create table Info(enum('男','女','选择保密')); # 下标从 1 开始:男 --> 1 ; 女 --> 2 ; 选择保密 --> 3 MySQL中实际存储的是编号,而不是列表中的值 # 数据插入示例 insert into Info values('男'); #方式一 插入一条性别为 "男" 的记录 insert into Info values(2); #方式二 插入一天性别为 "女" 的记录
-
set set类型, 可插入属性 值集合中的一个或多个 取多个值的时候,不同元素之间用 ‘逗号’ 隔开
# 格式 属性名 enum('值1','值2',...,'值n') # 创建表单示例 create table hobbies(sex('电竞','健身','影视','文学')); # 采用二进制方案,类似于Linux权限 这里采用4个二进制位 分别和属性值一一对应. 0001 --> 文学 ; 0010 --> 影视 ; 0011 --> 影视+文学 ... 依次类推 1111 --> 电竞+健身+影视+文学 # 数据插入示例 insert into hobbies values('电竞,文学'); # 插入爱好为 电竞+文学 的记录 注意在一个引号类 insert into hobbies values(1001); # 等同于上面一条语句 插入爱好为 电竞+文学 的记录
MySQL建表约束
-
主键约束
-
它能够唯一确定一张表中的一条记录,也就是我们通过给某个字段添加约束,就可以使得该字段不重复且不为空
-
create table table_name ( id int primary key, # id为属性名,可以修改,在表中不能插入相同id的成员且id不能为空 name varchar(20) )
-
联合主键
create table table_name ( id int, name varchar(20), primary key(id,name) # 只要求 id 和 name 有一个不重复就可以添加 );
-
添加主键约束
# 注意: 如果在创建数据表的时候,忘记创建主键约束了,可以通过如下语句添加 方法一: alter table table_name add primary key(id); # id 为想要添加主键约束的字段 方法二: alter table table_name modify id int primary key; # 删除主键约束 alter table table_name drop primary key;
-
-
自增约束
-
AUTO_INCREMENT : 在需要产生唯一标识符或顺序值时,可利用此属性,这个属性只用于整数类型。AUTO_INCREMENT 值一般从 1 开始,每行增加 1。 一个表中最多只能有一个 AUTO_INCREMENT列 。对于任何想要使用 AUTO_INCREMENT 的列,应该定义为 NOT NULL,并定义为 PRIMARY KEY 或定义为 UNIQUE 键。(auto_increment 与primary key 或则 unique 没有先后顺序之分),当指定为 unique (唯一约束)时,插入 id 的值可以为NULL,但实则和不指定一样,id 会按照前面的数字递增.
-
auto_increment是MySQL唯一扩展的完整性约束
-
auto_increment是在曾经存在过的最大值的基础上加一(哪怕最大值的记录删除了,也是在该值上加一)
-
MySQL8中,AUTO_INCREMENT必须设置为键(主键、外键和唯一键均可),否则会报错!(在使用外键的时候,也只是简单的在原来的基础上加一,并不是说会根据父表的值来增加)
-
create table table_name ( id int primary key auto_increment, # id 自增,可以不指定 id ,假如指定了 id name varchar(20) # 数据表就会按照 id 大小来排序 );
-
-
外键约束
-
涉及到两个表: 父表(主表) 子表(副表) 子表中某个字段的取值范围由父表决定, 即子表该字段依赖于父表中相应的字段 允许外键为空
-
# 举例 # 班级表 create table classes ( class_id int primary key, name varchar(20) ); # 学生表 create table students ( StuNO int primary key, name varchar(20), class_id int, foreign key(class_id) references classes(class_id) # class_id 绑定 班级表的 class_id ); # 解析:班级表是父表,学生表是子表,在学生表(子表)中添加成员时,要参考父表中的成员,要求与父表一致 # 1.主表中没有的数据值,在子表中是不可以使用的 # 2.主表中的记录被副表引用,那么解除联系之前,主表是不可以被删除的
-
-
唯一约束
-
约束修饰的字段的值不可以重复,和主键约束的区别是字段可以为空.
-
unique允许受约束的字段出现多个空值,NULL不算重复
-
# 方式一: create table user ( id int, name varchar(20), unique(name) # 唯一约束 UNI ); # 方式二: create table user( id int, name varchar(20) unique ); # 方式三 多个唯一约束 create table user ( id int, name varchar(20), unique(id,name) # 添加的成员 id 和 name 至少有一个不一样 MUL );
-
# 添加唯一约束 方式一: alter table table_name add unique(table_property); 方式二: alter table table_name modify name varchar(20) unique; # 删除唯一约束 alter table table_name drop index table_property;
-
-
非空约束
-
修饰的字段不能为空 NULL
-
create table table_name ( id int, name varchar(20) not null # NULL --->no );
-
-
默认约束
-
在插入字段的时候,如果没有指定默认约束属性的值,就会使用默认的值
-
create table table_name ( name varchar(20), id int default 10 # 当插入时,若 id 的值没有指定,则 id 为默认值 10,如果传递了值,就是 用传递的值 );
-
-
约束的删除
-
主键
alter table table_name drop primary key
-
外键或唯一键
alter table table_name drop index 约束的字段名
-
修改默认值、自增长和非空
# 增加或删除默认约束、自增长和非空约束的时候直接使用下列语句重定义即可 alter table table_name modify 列名 类定义 # 示例 (为class表添加默认约束和非空约束) alter table class modify name varchar(20) DEFAULT 'Tom' NOT NULL;
-
更新数据
update table_name set table_property =' new_value' where another_property = ' the value '
要更改的数据表属性 更改后的值 另一个属性 数据表中对应的值
# 更新所有的数据 两种方式
update table_name set table_property ='new_value';
update table_name set table_property ='new_value' where 1=1;
数据增删改
-
删除一个表单中所有的数据记录
-
delete from table_name where 1=1; # 删除表单 StudInfo 中所有的数据记录 delete from StudInfo where 1=1;
-
数据据索引
-
唯一索引
-
限制该索引的字段必须唯一
-
创建的格式 — 在创建普通索引的基础上,INDEX 前面加上 unique 限制即可.
-
创建表时创建索引
# [] --> 可选部分 create table table_name ( property1 type1, property2 type2, ...... propertyn typen, UNIQUE INDEX | KEY [indexname](property[length] [ASC | DESC])) # 不指明升降序则默认是升序
-
在已经存在的表上创建索引
# 方法一: 执行create语句 create UNIQUE INDEX indexname ON table_name(property [(length)] [ASC |DESC]); #方法二: 执行alter table语句 alter table table_name add UNIQUE INDEX | KEY indexname(property [(length)] [ASC |DESC]);
-
-
-
全文索引(英文)
-
全文索引主要对字符串类型建立基于分词的索引,所谓分词,所有非字母和数字的特数符号都是分词
-
全文索引才用关键字 FULLTEXT,创建格式和前面如出一辙
-
create table table_name ( property1 type1, property2 type2, ...... propertyn typen, FULLTEXT INDEX | KEY [indexname](property[length] [ASC | DESC])) # 不指明升降序则默认是升序
-
全文索引的查询
# 格式 table_name --> 表名 property_index --> 全文索引字段 contents --> 查找的内容 select * from table_name where match(property_index) AGINST('contents') # 示例 插入之中的内容所以分开,是形成多个分词 create table class(name varchar(64),FULLTEXT INDEX index_name(name)); insert into class values('我们 是一个 大家族'); # 查询 "我们"、"是一个"、"大家族" 均可查询到. 但是查询 "我们是一个大家族" 就无法查询到 select * from class where match(name) AGAINST('大家族');
-
查询时有意思的地方
-
# INDEX 全文索引 英文 在MySQL中使用全文索引的时候,默认要求单个单词中字母的个数大于2个才能查询到 create table class(id int,comment varchar(64),FULLTEXT INDEX index_full(comment)); insert into class values(1,'Hi,My name is Tom'); insert into class values(2,'hello,are you ok'); # 在MySQL中使用全文索引的时候,默认要求单个单词中字母的个数大于2个才能查询到 请看下面的示例 select * from class where match(comment) AGAINST('is') # 因为字母的数量小于3,所以查询失败 select * from class where match(comment) AGAINST('Tom'); # 因为这个单词字母的额数量大2,且在comment字段中拥有,则封装成功
-
-
全文索引(中文)
- 如何配置:在MySQL的配置文件my.ini(Windows 10 默认路径是:C:\ProgramData\MySQL\MySQL Server 8.0)文件中增加如下配置项,配置完成后需要重启MySQL80。
- 中文索引也是按照分词的方式来建立索引的,比如
-
单列索引
-
多列索引
-
多列索引,是指在创建索引时所关联的字段不是一个字段,而是多个字段,虽然可以通过所关联的字段进行查询,但是只有查询条件中使用了所关联字段中的第一个字段,多列索引才会被使用。
-
# 多列索引 create table class(id int,name varchar(20) UNIQUE,teacher varchar(64),index index_mult_col(id,teacher)); insert into class values(1,'一班','Rock'); insert into class values(2,'二班','Martian'); explain select * from class where id > 0; # 使用多列索引 因为使用了id字段,所以使用到了index_mult_col索引 +----+-------------+-------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+ | 1 | SIMPLE | class | NULL | range | index_mult_col | index_mult_col | 5 | NULL | 2 | 100.00 | Using index condition | +----+-------------+-------+------------+-------+----------------+----------------+---------+------+------+----------+-----------------------+ 1 row in set, 1 warning (0.00 sec) explain select * from class where teacher='Rock'; # 因为没有使用到id字段,所以没有使用到index_mult_col索引 +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | id | select_type | table | partitions | type | possible_keys | key | key_len | ref | rows | filtered | Extra | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ | 1 | SIMPLE | class | NULL | ALL | NULL | NULL | NULL | NULL | 2 | 50.00 | Using where | +----+-------------+-------+------------+------+---------------+------+---------+------+------+----------+-------------+ 1 row in set, 1 warning (0.00 sec)
-
-
全文索引
-
空间索引
-
使用建议
-
当索引存在的时候,每次插入数据的时候数据库系统会按照索引进行排序,再插入,在很大的程度上降低了数据插入的效率,所以在已经建有索引的数据库中插入大量的数据的时候,建议先将索引删除,之后子啊插入数据,数据插入完毕之后在恢复索引
-
普通索引
-
创建索引的时候,不需要附加任何限制条件,可以创建在任何数据类型的字段上
-
创建的格式
- 创建表时创建索引
# [] --> 可选部分 create table table_name ( property1 type1, property2 type2, ...... propertyn typen, INDEX | KEY [indexname](property[length] [ASC | DESC])) # 不指明升降序则默认是升序 # 用中文描述格式即: create table table_name ( 字段1 类型1, 字段2 类型2, ..... 字段n 类型n, INDEX | KEY [自定义索引名字](索引字段[索引字段长度][ASC | DESC]))
-
在已存在的表上创建索引
# 方法一: 执行create语句 create INDEX indexname ON table_name(property [(length)] [ASC |DESC]); #方法二: 执行alter table语句 alter table table_name add INDEX | KEY indexname(property [(length)] [ASC |DESC]);
-
查看索引使用的情况 —> EXPLAIN
EXPLAIN select * from table_name where id = 1; # 查询结果部分参数意义: key: 实际使用的索引。如果为NULL,则没有使用索引 possible_keys:显示可能应用在这张表中的索引,一个或多个。查询涉及到的字段上若存在索引,则该索引 将被列出,但不一定被查询实际使用 key_len: 表示索引中使用的字节数,可通过该列计算查询中使用的索引的长度。此值越短越好!
-
-
隐藏索引
-
MySQL 8开始支持隐藏索引。隐藏索引提供了更人性化的数据库操作。隐藏索引,顾名思义,让索引暂时不可见,不会被优化器使用。默认情况下索引是可见的。隐藏索引可以用来测试索引的性能。验证索引的必要性时不需要删除索引,可以先将索引隐藏,如果优化器性能无影响就可以真正地删除索引。
-
ALTER TABLE tablename ALTER INDEX index_name INVISIBLE; #隐藏索引 成功隐藏索引之后,使用show create table table_name查看表的结构时会发现在你所隐藏的索引后面会有一句 /*!80000 INVISIBLE */ .并且使用explain解释查询的时候发现,没有使用该字段作为索引 ALTER TABLE tablename ALTER INDEX index_name VISIBLE; #取消隐藏 恢复隐藏索引之前的样式
-
-
删除索引
-
所谓删除索引,就是删除表中已经创建的索引。之所以要删除索引,是因为这些索引会降低表的更新速度,影响数据库的性能。在MySQL中删除索引通过SQL语句DROP INDEX来实现,其语法形式如下:
-
DROP INDEX indexname ON tablename;
-
数据查询
-
查询数据表的所有记录
-
select * from table_name; # * 表示所有字段记录
-
-
查询数据表 table_name 中所有记录的 table_property1,table_property2属性字段(列)的值
-
# * 表示所有字段 select table_property1,table_property2 from table_name; # EG select StuNO,StuName from StudInfo; # 查询StuInfo表中学号(StuNO)和姓名(StuName)信息
-
-
查询数据表中所有的table_property属性不重复的字段(列) —>即假如有相同的属性值只列出一个即可,
-
# distinct 排除重复 select distinct table_property from table_name;
-
-
查询数据表 score 中分数在 60 - 80 之间中的所有记录 score 为分数表 degree 为成绩
-
# 方式一:查询区间 between .... and ...... (闭区间,包含两端) select * from score where degree between 60 and 80; # 方式二:直接使用运算符比较 select * from score where degree > 60 and degree < 80;
-
-
查询数据表 score 中分数为 85 , 86 , 88 的记录 score 为分数表 degree 为成绩
-
# in 表示或者关系的查询 select * from score where degree in (85,86,88);
-
-
查询数据表 student 中班级为 ‘95031’ 或者性别为 ‘女’ 的同学的记录
-
# or 表示或者 select * from student where class='95031' or sex='女';
-
-
以 class 升降序查询 student 表所有记录
-
# 升序排列查看 ascend 上升 一般默认是升序 select * from student order by class asc; # 降序排列查看 descend 下降 select * from student order by class desc;
-
-
以 cno升序, degree 降序排序查询表 score 的所有记录
-
# 在表中先以 cno 升序排列,然后对于 cno 相同的记录,按照 degree 降序排列 select * from score order by cno asc,degree desc;
-
-
查询 ‘95031’ 班的学生人数
-
# 统计 count select count(*) from student where class='95031';
-
-
查询表 score 中的最高分的学生学号和课程号. (子查询或者排序)
-
# 方式一. 子查询 步骤 # 1.找到最高分 ---> select max(degree) from score # 2.找到最高分的 sno 和 cno # 最终代码: select sno,cno from score where degree=(select max(degree) from score); # 方式二. 排序的做法 ---> 先降序排列,然后拿到第一个数据 但是有缺陷,计入有两个及以上最高分//时,只会输出其中一个 不得不说,想法还挺多QAQ # limit 第一个数字表示从多少开始, 第二个数字表示查多少条 select sno,cno,degree from score order by degree desc limit 0,1;
-
-
查询每门课的平均成绩
-
# 计算指定一门课的平均成绩 --- 下面计算课程编号为 3-105 的课程的成绩 select avg(degree) from score where cno='3-105'; # 计算每门课的平均成绩 --- cno 课程编号 # group by 分组 group by cno -->就是按照课程编号分组 # 1.只打印打印平均成绩和课程编号 select cno,avg(degree) from score group by cno; # 2.打印平均成绩和所有 score 表的其他属性信息 --- * 后面要跟一个 ',',否则会失败 selec * ,avg(degree) from score group by cno;
-
-
查询 score 表中至少有两名学生选修的并以3开头的课程的平均成绩
-
# 1.找到至少有两名学生选修的课程 cno --- 课程编号 # having 表示分组后的条件 select cno from score group by cno having count(cno) >=2; # 2.在上面的基础上在添加课程编号以 3 的要求 # like 模糊查询 # % --- >通配符 select cno from score group by cno -->having count(cno)>=2 and cno like '3%' # 3.在上面的基础上计算平均成绩 select cno,avg(degree) from score group by cno -->having count(cno)>=2 and cno like '3%'
-
-
查询所有学生的 sname, cno 和 degree 列. ----> 多表查询
-
# 查询 student 表中的 sname select sname from student; # 查询 score 表中的 cno,degree select cno,degree from score; # 最终代码 select sname,cno,degree from student,score where student.sno=score.sno; # 解释 当 student 中的 sno 等于 score 中的 sno 时候,就用student 表中的 sname 代替 score 表中的 cno,从而达到查询目的
-
-
查询 “95031” 班学生每门课的平均分
-
# 1.查询 student 表中班级为 95031 的学生的编号 select sno from student where class='95031'; # 2.按照上面的 sno (即班级为 95031 学生的 sno) 查询 score 表中相应地学生 ----> score 表中有 sno 没有班级字段,所以按照上面两个步骤就可以 找出 score 表中班级为 95031 的学生了 # 最终代码 (计算平均成绩是要按分组计算的哟) select cno,avg(degree) from score where sno in (select sno from student where class='95031') group by cno;
-
查询和学号为108,101的同学同年出生的所有学生的sno,sname和sbirthday列
-
# 1.查询学号为108,101的同学是谁 select * from student where sno in(108,101); # 2.查询这两个学生的出生年 select year(sbirthday) from student where sno in(108,101); # 最终代码 select * from student where year(sbirthday) in (select year(sbirthday) from student where sno in(108,101));
-
-
查询"计算机系"与"电子工程系"不同职称的教师的 tname 和 prof
-
# 1.电子工程系的职称 select Prof from teacher where depart='电子工程系'; # 2.查询计算机系中没有与电子工程系教师职称相同的记录 not in 不包含 select * from teacher where depart='计算机系' and prof not in(select prof from teacher where depart='电子工程系'); # 最终代码 union ----> 求并集 select * from teacher where depart='计算机系' and prof not in(select prof from teacher where depart='电子工程系') union select * from teacher where depart='电子工程系' and prof not in(select prof from teacher where depart='计算机系');
-
-
查询选修编号为“3-105”课程且成绩至少高于选修编号为“3-245”的同学的Cno,Sno和Degree,并按Degree从高到低次序排列
-
# 1.选修课程编号 “3-105” 的同学 select * from score where cno='3-105'; # 2.选修课程编号为 “3-245” 的同学 select * from score where cno='3-245'; # 至少? 大于其中至少一个, any select * from score where cno='3-105' and degree > any(select degree from score where cno='3-245'); # 最终代码 select * from score where cno='3-105' and degree > any(select degree from score where cno='3-245') order by degree desc;
-
-
查询选修编号为“3-105”课程且成绩高于选修编号为“3-245”所有同学的Cno,Sno和Degree,并按Degree从高到低次序排列
-
# all 表示所有 select * from score where cno='3-105' and degree > all(select degree from score where cno='3-245');
-
SQL 的四种连接查询
- 内连接 ----> inner join 或者 join
- 内联查询 : 其实就是两张表中的数据,通过某个字段相等,查询出相关记录数据.
- 外连接
- 左连接 ----> left join 或者 left outer join
- 左外连接,会把左边表里面的所有的数据取出来,而右边表中的数据,如果有相等的,就显示出来,如果没有,就会补 NULL
- 右连接 ----> right join 或者 right outer join
- 右外连接,会把右边表里面的所有数据取出来,而左边表中的数据,如果有相等的,就会显示出来,如果没有相等的,就会补 NULL
- 完全外连接 ----> full join 或者 full outer join
- 左连接 ----> left join 或者 left outer join
数据库的三大设计范式
- 第一范式 -----> 1NF
- 数据表中所有的字段都是不可分割的原子值
- 字段值还可以继续拆分的就不满足第一范式
- 第二范式 ------>2NF
- 必须满足第一范式的前提下,第二范式要求,除主键外的每一列都必须完全依赖于主键
- 如果出现不完全依赖,只有可能发生在联合主键的情况下
- 百度百科详解及举例
- 第三范式 ------->3NF
- 必须先满足第二范式,除开主键列外的其他列之间不能有传递依赖关系
- 百度百科
MySQL事务
-
mysql 中,事务其实是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性。
# 比如我们的银行转账 a --> -100 update user set money=money-100 where name='a'; b --> +100 update user set money=money+100 where name='b'; # 实际的程序中,如果只有一条语句执行成功了,而另一条没有执行成功,就会出现数据前后不一致 # 多条 SQL 语句,可能会有同时成功的要求,要么就同时失败.
-
mysql 中如何控制事务
-
MySQL 默认是开启事务的(自动提交).
select @@autocommit; # 作用 : 当我们去执行一个 SQL 语句时候,效果就会立即体现出来,且不能回滚. # 事务回滚 : 撤销 SQL 语句执行效果 rollback; # 设置 mysql 自动提交为 false (关闭自动提交) set autocommit=0; # 手动提交数据 commit; # begin 或者 start transaction 都可以 帮我们手动开启一个事务
-
事务的四大特征
- A : 原子性 : 事务是最小的单位,不可以再分割
- C : 一致性 : 事务要求,同一事务中的 SQL 语句,必须保证同时成功或者同时失败.
- I : 隔离性 : 事务1 和事务2 之间是具有隔离性的.
- D : 持久性 : 事务一旦结束 (commit ,rollback),就不可以返回.
-
事务的隔离性
-
read uncommitted ----> 读未提交的
# 如果有事务a,和事务b. # a 事务对数据进行操作,在操作过程中,事务没有被提交,但是b 可以看见 a 操作的结果. # 如何查看数据库的隔离级别 8.0版本 1. 系统级别 select @@global.transaction_isolation +--------------------------------+ | @@global.transaction_isolation | +--------------------------------+ | REPEATABLE-READ | +--------------------------------+ 2.会话级别 select @@transaction_isolation +-------------------------+ | @@transaction_isolation | +-------------------------+ | REPEATABLE-READ | +-------------------------+ # 如何修改隔离级别 set global transaction isolation level read uncommitted; # 脏读 一个事务读取到了另一个事务没有提交的数据,就叫做脏读
-
read committed ----> 读已经提交的
# 虽然只读到另外一个事务提交的数据,但还是会出现问题,就是读取同一个表的数据,发现前后不一致.即不可重复读现象
-
repeatable read ----> 可以重复读
# 幻读 -- 事务 a 和事务 b 同时操作一张表,事务 a 提交的数据,也不能被事务 b 读到,就可以造成幻读
-
serializable ----> 串行话化
# 当一个表被另一个事务操作时候,其他事务里面的写操作,是不可以进行的.进入排队 状态(串行化),直到该事务结束之后,其他事务的写操作才会执行. # 串行化的问题是,性能特差 -- 性能: READ-UNCOMMITTED > READ-COMMITTED > REPEATABLE-READ > SERIALIZABLE -- 隔离级别越高,性能越差 -- mysql 默认隔离级别是 REPEATABLE-READ
-
MySQL 浮点型和定点型可以用类型名称后加(M,D)来表示,M表示该值的总共长度,D表示小数点后面的长度,M和D又称为精度和标度