登录和退出MySQL服务器
1 | #登陆 |
增删改查基本语法
1 | -- 显示所有数据库 |
mysql 建表约束
主键约束:
1 | -- 主键约束 |
唯一约束:
1 | -- 建表时创建唯一字段 |
非空约束:
1 | -- 建表时添加非空约束 |
默认约束:
1 | -- 建表时添加默认约束 |
外键约束:
1 | -- 外键约束 |
数据表设计-三大范式
1NF
只要字段值还可以继续拆分,就不满足第一范式。
范式设计得越详细,对某些实际操作可能会更好,但并非都有好处,需要对项目的实际情况进行设定。
1 | address>>- country | province | city | details | |
2NF
在满足第一范式的前提下,其他列都必须完全依赖于主键列。如果出现不完全依赖,只可能发生在联合主键的情况下:
1 | -- 订单表 |
实际上,在这张订单表中,product_name 只依赖于 product_id ,customer_name 只依赖于 customer_id 。也就是说,product_name和 customer_id 是没用关系的,customer_name 和 product_id 也是没有关系的。
这就不满足第二范式:其他列都必须完全依赖于主键列!–>拆分!
1 | CREATE TABLE myorder ( |
拆分之后,myorder 表中的 product_id 和 customer_id 完全依赖于 order_id 主键,而 product 和 customer 表中的其他字段又完全依赖于主键。满足了第二范式的设计!
3NF
在满足第二范式的前提下,除了主键列之外,其他列之间不能有传递依赖关系。
1 | CREATE TABLE myorder ( |
表中的 customer_phone 有可能依赖于除了 customer_id 之外的 order_id 列,也就不满足了第三范式的设计:除了主键列之外,其他列之间不能有传递依赖关系。
1 | CREATE TABLE myorder ( |
修改后就不存在其他列之间的传递依赖关系,其他列都只依赖于主键列,满足了第三范式的设计!
mysql查询练习
准备数据
创建表:学生表(student)、教师表(teacher)、成绩表(score)、课程表(course)
1 | -- 创建学生表 |
添加数据:
1 | -- 添加学生表数据 |
十道练习题
1 | -- 1.查询student表中所有记录 |
分组计算平均成绩
1 | -- 查询每门课的平均成绩 |
分组条件与模糊查询
1 | -- 查询 score 表中至少有 2 名学生选修,并以 3 开头的课程的平均分数 |
多表查询
查询所有学生的 name,以及该学生在 score 表中对应的 c_no 和 degree :
1 | -- SELECT no, name FROM student; |
查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列:
1 | -- 查询所有学生的 no 、课程名称 ( course 表中的 name ) 和成绩 ( score 表中的 degree ) 列 |
三表关联查询
查询所有学生的 name 、课程名 ( course 表中的 name ) 和 degree :
1 | -- 查询所有学生的 `name` 、课程名 ( `course` 表中的 `name` ) 和 `degree` |
子查询加分组求平均分
查询 95031 班学生每门课程的平均成绩:
1 | -- 查询 95031 班学生每门课程的平均成绩 |
子查询
查询在 3-105 课程中,所有成绩高于 109 号同学的记录:
1 | -- 查询在 3-105 课程中,所有成绩高于 109 号同学的记录 |
YEAR 函数与带 IN 关键字查询
查询所有和 101 、108 号学生同年出生的 no 、name 、birthday 列
1 | -- 查询所有和 `101` 、`108` 号学生同年出生的 `no` 、`name` 、`birthday` 列 |
多层嵌套子查询
查询 '张旭' 教师任课的学生成绩表
1 | -- 查询 '张旭' 教师任课的学生成绩表 |
多表查询
查询某选修课程多于5个同学的教师姓名
1 | -- 查询某选修课程多于5个同学的教师姓名 |
子查询-2
查询计算机系所有老师的上的课的成绩表
1 | -- 查询计算机系所有老师的上的课的成绩表 |
UNION 和 NOT IN 的使用
1 | -- 查询 计算机系 与 电子工程系 中的不同职称的教师 |
ANY 表示至少一个 - DESC ( 降序 )
查询课程 3-105 且成绩 至少 高于 3-245 的 score 表(大于 3-245 的最小值)
1 | -- 查询课程 `3-105` 且成绩 至少 高于 `3-245` 的 `score` 表 |
表示所有的 ALL
查询课程 3-105 且成绩高于 3-245 的 score 表
1 | -- 查询课程 3-105 且成绩高于 3-245 的 score 表 |
复制表的数据作为条件查询
查询某课程成绩比该课程平均成绩低的 score 表
1 | -- 查询某课程成绩比该课程平均成绩低的 `score` 表 |
子查询 - 4
查询所有任课 ( 在 course 表里有课程 ) 教师的 name 和 department
1 | -- 查询所有任课 ( 在 `course` 表里有课程 ) 教师的 `name` 和 `department` |
条件加组筛选
查询 student 表中至少有 2 名男生的 class
1 | -- 查询 `student` 表中至少有 2 名男生的 `class` |
NOTLIKE 模糊查询取反
查询 student 表中不姓 “王” 的同学记录
1 | -- NOT: 取反 |
YEAR 与 NOW 函数
查询 student 表中每个学生的姓名和年龄
1 | -- 查询 `student` 表中每个学生的姓名和年龄 |
MAX 与 MIN 函数
查询 student 表中最大和最小的 birthday 值
1 | -- 查询 `student` 表中最大和最小的 `birthday` 值 |
多段排序
以 class 和 birthday 从大到小的顺序查询 student 表
1 | -- 以 `class` 和 `birthday` 从大到小的顺序查询 `student` 表 |
子查询 - 5
查询 “男” 教师及其所上的课程
1 | -- 查询 "男" 教师及其所上的课程 |
MAX 函数与子查询
查询最高分同学的 score
1 | -- 查询最高分同学的 `score` |
子查询 - 6
查询和 “李军” 同性别的所有同学 name
1 | -- 查询和 "李军" 同性别的所有同学 `name` |
子查询 - 7
查询和 “李军” 同性别且同班的同学 name
1 | -- 查询和 "李军" 同性别且同班的同学 `name` |
子查询 - 8
查询所有选修 “计算机导论” 课程的 “男” 同学成绩表
需要的 “计算机导论” 和性别为 “男” 的编号可以在 course 和 student 表中找到
1 | -- 查询所有选修 "计算机导论" 课程的 "男" 同学成绩表 |
按等级查询
1 | -- 建立一个 `grade` 表代表学生的成绩等级,并插入数据 |
mysql连接查询

准备数据:
1 | CREATE DATABASE testJoin; |
分析两张表发现,person 表并没有为 cardId 字段设置一个在 card 表中对应的 id 外键。如果设置了的话,person 中 cardId 字段值为 6 的行就插不进去,因为该 cardId 值在 card 表中并没有
内连接
inner join 或者 join
要查询这两张表中有关系的数据,可以使用 INNER JOIN ( 内连接 ) 将它们连接在一起
1 | select * from person inner join card on person.cardId = card.id; |
注意:card 的整张表被连接到了右边
外链接
左外连接:left join 或者 left outer join
完整显示左边的表 ( person ) ,右边的表如果符合条件就显示,不符合则补 NULL
1 | select * from person left join card on person.cardId = card.id; |
右外连接:right join 或者 right outer join
完整显示右边的表 ( card ) ,左边的表如果符合条件就显示,不符合则补 NULL
1 | select * from person right join card on person.cardId = card.id; |
完全连接:full join 或者 full outer join
1 | -- mysql 不支持全连接语法 |
事务
在 MySQL 中,事务其实是一个最小的不可分割的工作单元。事务能够保证一个业务的完整性。
1 | -- 比如我们的银行转账: |
在实际项目中,假设只有一条 SQL 语句执行成功,而另外一条执行失败了,就会出现数据前后不一致。
因此,在执行多条有关联 SQL 语句时,事务会要求这些 SQL 语句要么同时执行成功,要么就都执行失败。
如何控制事务 - COMMIT / ROLLBACK
在 MySQL 中,事务的自动提交状态默认是开启的
1 | -- 查询事务的自动提交状态 |
自动提交的作用:当我们执行一条 SQL 语句的时候,其产生的效果就会立即体现出来,且不能回滚。
什么是回滚?举个例子:
1 | CREATE DATABASE bank; |
可以看到,在执行插入语句后数据立刻生效,原因是 MySQL 中的事务自动将它提交到了数据库中。那么所谓回滚的意思就是,撤销执行过的所有 SQL 语句,使其回滚到最后一次提交数据时的状态。
在 MySQL 中使用 ROLLBACK 执行回滚:
1 | -- 回滚到最后一次提交 |
由于所有执行过的 SQL 语句都已经被提交过了,所以数据并没有发生回滚。那如何让数据可以发生回滚: 设置AUTOCOMMIT = 0;
1 | -- 关闭自动提交 |
总结:
自动提交
- 查看自动提交状态:
SELECT @@AUTOCOMMIT; - 设置自动提交状态:
SET AUTOCOMMIT = 0。
- 查看自动提交状态:
手动提交
@@AUTOCOMMIT = 0时,使用COMMIT命令提交事务。事务回滚
@@AUTOCOMMIT = 0时,使用ROLLBACK命令回滚事务。
1 | -- 测试银行转账 |
这时我们又回到了发生意外之前的状态,也就是说,事务给我们提供了一个可以反悔的机会。假设数据没有发生意外,这时可以手动将数据真正提交到数据表中:COMMIT
手动开启事务 - BEGIN / START TRANSACTION
1 | -- 设置为自动提交 |
事务的默认提交被开启 ( @@AUTOCOMMIT = 1 ) 后,此时就不能使用事务回滚了。但是我们还可以手动开启一个事务处理事件,使其可以发生回滚:
使用 BEGIN 或者 START TRANSACTION 手动开启一个事务:
1 | -- 使用 BEGIN 或者 START TRANSACTION 手动开启一个事务 |
事务的 ACID 特征与使用
事务的四大特征:
A(Atomicity):原子性:事务是最小的单位,不可以再分割;
C(Consistency):一致性:要求同一事务中的 SQL 语句,必须保证同时成功或者失败;
I(Isolation): 隔离性:事务1 和 事务2 之间是具有隔离性的;
D(Durability):持久性:事务一旦结束 ( COMMIT ) ,就不可以再返回了 ( ROLLBACK ) ;
事务的隔离性可分为四种 ( 性能从低到高 ) :
READ - UNCOMMITTED ( 读取未提交 )
如果有多个事务,那么任意事务都可以看见其他事务的未提交数据。
READ - COMMITTED ( 读取已提交 )
只能读取到其他事务已经提交的数据。
REPEATABLE - READ ( 可被重复读 )
如果有多个连接都开启了事务,那么事务之间不能共享数据记录,否则只能共享已提交的记录。
SERIALIZABLE ( 串行化 )
所有的事务都会按照固定顺序执行,执行完一个事务后再继续执行下一个事务的写入操作。
1 | -- 查看当前数据库的默认隔离级别: |
脏读:READ UNCOMMITTED ( 读取未提交 )
一个事务读取到另外一个事务还未提交的数据。这在实际开发中是不允许出现的;
如果此时 rollback ,之前操作的数据就会失效
不可重复读:读取已提交:READ - COMMITTED ( 读取已提交 )
虽然 READ COMMITTED 让我们只能读取到其他事务已经提交的数据,但还是会出现问题,就是在读取同一个表的数据时,可能会发生前后不一致的情况。这被称为不可重复读现象 ( READ COMMITTED )
幻读:REPEATABLE - READ ( 可被重复读 )
当前事务开启后,没提交之前,查询不到,提交后可以被查询到。但是,在提交之前其他事务被开启了,那么在这条事务线上,就不会查询到当前有操作事务的连接。相当于开辟出一条单独的线程。
无论小张是否执行过 COMMIT ,在小王这边,都不会查询到小张的事务记录,而是只会查询到自己所处事务的记录
1 | -- 小张 - 成都 |
这是因为小王在此之前开启了一个新的事务 ( START TRANSACTION ) ,那么在他的这条新事务的线上,跟其他事务是没有联系的,也就是说,此时如果其他事务正在操作数据,它是不知道的。
然而事实是,在真实的数据表中,小张已经插入了一条数据
串行化:SERIALIZABLE ( 串行化 )
1 | -- 设置隔离级别 |
此时会发生什么呢?由于现在的隔离级别是 SERIALIZABLE ( 串行化 ) ,串行化的意思就是:假设把所有的事务都放在一个串行的队列中,那么所有的事务都会按照固定顺序执行,执行完一个事务后再继续执行下一个事务的写入操作 ( 这意味着队列中同时只能执行一个事务的写入操作 ) 。
根据这个解释,小王在插入数据时,会出现等待状态,直到小张执行 COMMIT 结束它所处的事务,或者出现等待超时。 所以性能较差