学习视频链接:https://www.bilibili.com/video/BV1Kr4y1i7ru/?spm_id_from=333.999.0.0&vd_source=619f8ed6df662d99db4b3673d1d3ddcb
基础篇——MySQL概述、SQL、函数、约束、多表查询、事务
进阶篇——存储引擎、索引、SQL优化、视图/存储过程/触发器、锁、InnoDB核心、MySQL管理
运维篇——日志、主从赋值、分库分表、读写分离
数据库(DataBase, DB):存储数据的仓库,数据在其中是有组织存储的
|
数据库管理系统(DataBase Management System, DBMS):操作和管理数据库的软件
|
SQL(Structured Query Language):操作数据库的语言,一套标准
主流的关系型数据库
安装
启动及停止
客户端进行连接
数据模型
数据库分类
注意事项:
分类:
1)DDL-数据库操作
-- 查询所有的数据库
SHOW DATABASES;
-- 查询当前数据库
SELECT DATABASE();
# 创建 utf8mb4
CREATE DATABASE [IF NOT EXISTS] 数据库名 [DEFAULT CHARSET 字符集] [COLLATE 排序规则];
# 删除
DROP DATABASE [IF EXISTS] 数据库名;
# 使用
USE 数据库名
2)DDL-表查询
-- 查询当前数据库的所有表
SHOW TABLES;
-- 查询表结构
DESC 表名;
-- 查询指定表的建表语句
SHOW CREATE TABLE 表名;
3)DDL-表创建
create table tb_user(
-> id int comment '编号',
-> name varchar(50) comment '姓名',
-> age int comment '年龄',
-> gender varchar(1) comment '性别'
-> )comment '用户表';
creat table 表名(
字段名 字段类型 [comment 字段注释],
……
字段名 字段类型 [comment 字段注释]
)[comment 表注释];
字段类型
数值类型
字符类型
日期时间类型
4)DDL-表操作-修改
# 字段
-- 添加字段
ALTER TABLE 表名 ADD 字段名 类型(长度) [COMMENT 注释] [约束];
-- 修改数据类型
ALTER TABLE 表名 MODIFY 字段名 新数据类型(长度);
-- 修改字段名和字段类型
ALTER TABLE 表名 CHANGE 旧字段名 新字段名 类型(长度) [COMMENT 注释] [约束];
-- 删除
ALTER TABLE 表名 DROP 字段名;
# 表
-- 修改表名
ALTER TABLE 表名 RENAME TO 新表名;
-- 删除
DROP TABLE [IF EXISTS] 表名;
-- 删除指定表,并重新创建该表,保留表结构
TRUNCATE TABLE 表名;
-- 添加数据 字符串和日期类型要用引号引起来
INSERT
# 给指定字段添加数据
INSERT INTO 表名(字段名1, 字段名2,……) VALUES (值1, 值2, ……);
# 给全部数据添加字段
INSERT INTO 表名 VALUES (值1, 值2, ……);
# 批量添加数据
INSERT INTO 表名(字段名1, 字段名2,……) VALUES (值1, 值2, ……), (值1, 值2, ……), (值1, 值2, ……);
INSERT INTO 表名 VALUES (值1, 值2, ……), (值1, 值2, ……), (值1, 值2, ……);
-- 修改数据;如果不加条件,就会修改整张表的所有数据。
UPDATE
UPDATE 表名 SET 字段名1=值1, 字段名2=值2, … [WHERE 条件];
-- 删除数据
DELETE
DELETE FROM 表名 [where 条件];
DELETE不能删除某个字段的值,可以使用UPDATE,使用UPDATA修改表中数据为NULL
语法
SELECT
字段列表
FROM
表名列表
WHERE
条件列表
GROUP BY
分组字段列表
HAVING
分组后条件列表
ORDER BY
排序字段列表
LIMIT
分页参数
DQL-基本查询
# 查询多个字段
SELECT 字段1, 字段2, …… FROM 表名;
SELECT * FROM 表名; # 效率低,不直观
# 设置别名
SELECT 字段1 [AS 别名1], 字段1 [AS 别名1], …… FROM 表名;
# 去除重复记录
SELECT DISTINCT 字段列表 FROM 表名;
DQL-条件查询
SELECT 字段列表 FROM 表名 WHERE 条件列表;
聚合函数
概念: 将一列数据作为一个整体,进行纵向计算
常见聚合函数: count——统计数量
? max——最大值
? min——最小值
? avg——平均值
? sum——求和
注意:所有聚合函数不计算null值
SELECT 聚合函数(字段列表) FROM 表名;
分组查询
SELECT 字段列表 FROM 表名 [WHERE 条件] GROUP BY 分组字段名 [HAVING 分组后过滤条件];
/*
where 和 having 的区别
1. 执行时机:where是分组之前进行过滤,不满足where条件,不参与分组;having是分组之后对结果进行过滤
2. 判断条件不同:where不能对聚合函数进行判断,having可以
*/
-- 注意
-- 执行顺序:where > 聚合函数 > having
-- 分组之后,查询的字段一般为聚合函数和分组字段,查询其他字段无意义
排序查询
SELECT 字段列表 FROM 表名 ORDER BY 字段1 排序方式1, 字段2 排序方式2, ……;
# 排序方式
ASC 升序
DESC 降序
# 第一个字段排序后相等,才会执行第二个字段的排序
分页查询
# 语法
SELECT 字段列表 FROM 表名 LIMIT 起始索引, 查询记录数;
# 起始索引是0开始, 起始索引=(查询页码-1)*每页显示记录数
# 如果查询的是第一页的数据,起始索引可以省略
DQL-执行顺序
起别名要在执行顺序之后才能使用
哪些用户可以访问,每个用户有访问数据库的什么权限
DCL-管理用户:SQL开发人员操作少,主要是DBA(Database Administrator 数据库管理员)使用
# 1. 查询用户
USE mysql;
SELECT * FROM user;
# 2. 创建用户 %表示任意主机,localhost表示本机
CREATE USER '用户名'@'主机名' IDENTIFIED BY '密码';
# 3. 修改用户密码
ALTER USER '用户名'@'主机名' IDENTIFIED WITH mysql_native_password BY '新密码';
# 4. 删除用户
DROP USER '用户名'@'主机名';
DCL-权限控制
# 1. 查询权限
SHOW GRANTS FOR '用户名'@'主机名';
# 2. 授予权限 所有数据库的表*.*
# 权限之间用逗号分隔
GRANT 权限列表 ON 数据库名.表名 TO '用户名'@'主机名';
# 3. 撤销权限
REVOKE 权限列表 ON 数据库名.表名 FROM '用户名'@'主机名';
概念: 一段可以直接被调用的代码或程序
select now(); # 2023-12-20 08:57:50
select curtime(); # 08:59:47
select YEAR(now()); # 2023
select MONTH(now()); # 12
select day(now()); #20
select date_add(now(), INTERVAL 70 YEAR); # 2093-12-20 09:02:30
select date_add(now(), INTERVAL 70 MONTH); # 2029-10-20 09:02:42
select date_add(now(), INTERVAL 70 DAY); # 2024-02-28 09:02:53
select datediff('2023-1-10', '2023-1-1'); # 9
实现条件筛选,从而提高语句的效率
create table score
(
id int comment '编号',
name varchar(50) comment '姓名',
math double comment '数学成绩',
english double comment '英语成绩',
chinese double comment '语文成绩'
) comment '学员成绩表';
insert into score values (1, 'TOM', 67, 88, 95), (2, 'Rose', 23, 66, 90), (3, 'Jack', 56, 98, 76);
show create table score;
show tables;
select * from score;
select
id,
name,
(case when math >= 85 then '优秀' when math >= 60 then '及格' else '不及格' end) as 'math',
(case when english >= 85 then '优秀' when english >= 60 then '及格' else '不及格' end) as 'english',
(case when chinese >= 85 then '优秀' when chinese >= 60 then '及格' else '不及格' end) as 'chinese'
from score;
概念: 作用于表中字段上的规则,用于限制存储在表中的数据
目的: 保证数据库中数据的正确、有效和完整
时机: 创建表/修改表的时候添加约束
分类:
自动增长:AUTO_INCREMENT
create table user (
id int primary key auto_increment comment '主键',
name varchar(10) not null unique comment '姓名',
age int check ( age >0 and age <= 120 ) comment '年龄',
status char(1) default '1' comment '状态',
gender char(1) comment '性别'
) comment '用户表';
-- 什么情况下会使用那个默认值呢?? 不写要插入这个字段
-- 插入数据
insert into user(name, age, status,gender) values ('Tom1', '19', '1', '男'), ('Tom2', '20', '2', '男');
insert into user(name, age,status,gender) values('Tom3','80','1','男'); # 上面语句执行了两次,这条记录的编号是从5开始的
insert into user(name, age,status,gender) values(null,'80','1','男'); # null不占用编号
insert into user(name, age,status,gender) values('Tom4','80','1','男');
# 外键约束
CREATE TABLE 表名(
字段名 数据类型,
……
[CONSTRAINT] [外键名称] FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名);
);
ALTER TABLE 表名 ADD CONSTRAINT 外键名称 FOREIGN KEY (外键字段名) REFERENCES 主表 (主表列名);
一对多(多对一): 在多的一方建立外键,与少的一方的主键连接
多对多: 建立第三张中间表,中间表至少包含两个外键,分别关联两个主键
一对一: 用于单表拆分,将一张表的基础字段放在一张表中,其他详情字段放在另一张表中,提升操作效率。在任意一方加入外键,关联另外一方的主键,并且设置外键为唯一的(UNIQUE)
从多张表中查询数据——消除无效的笛卡尔积
需要限定条件where
查询A、B交集部分数据
# 隐式内连接
SELECT 字段列表 FROM 表1, 表2 WHERE 条件……;
# 显式内连接
SELECT 字段列表 FROM 表1 [INNER] JOIN 表2 ON 连接条件;
-- 显式内连接减少扫描,速度更快
左外连接:查询左表所有数据,以及两张表交集部分数据
右外连接:查询右表所有数据,以及两张表交集部分数据
# 左外连接
SELECT 字段列表 FROM 表1 LEFT [OUTER] JOIN 表2 ON 条件……;
# 右外连接
SELECT 字段列表 FROM 表1 RIGHT[OUTER] JOIN 表2 ON 条件……;
-- 换一下表的位置就无所谓左外还是右外连接
当前表与自身的连接查询,自连接必须使用表别名
SELECT 字段列表 FROM 表1 别名1 JOIN 表1 别名2 ON 条件……;
把多次查询的结果合并起来,形成一个新的查询结果集
# UNION 去重 UNION ALL 不去重
# 对于联合查询的多张表的列数必须保持一致,字段类型也需要保持一致
SELECT 字段列表 FROM 表A……
UNION/UNION ALL
SELECT 字段列表 FROM 表B……;
/*
* 为什么不用or
1. 联合查询效率更高,会使索引失效?
2. 一张表or方便,多张呢?
*/
概念: SQL语句中嵌套SELECT语句,称为嵌套查询 ,又称子查询
SELECT * FROM t1 WHERE column1 = (SELECT column1 FROM t2);
根据子查询结果分类
标量子查询(子查询结果是单个值)
# 子查询返回的结果是单个值(数字、字符串、日期等)
# 常用操作符
> >= < <= <> =
列子查询(子查询结果为一列)
# 常用操作符
IN——在指定的集合范围之内
NOT IN——不在指定的集合范围之内
ANY——子查询返回列表中,有任意一个满足即可
SOME——和ANY同
ALL——子查询返回列表的所有值都必须满足
行子查询(子查询结果为一行)
# 常用操作
=
<>
IN
NOT IN
SELECT * FROM emp WHERE (列1,列2) = (SELECT 列1, 列2 FROM ……)
表子查询(子查询结果为多行多列)
# 常用操作
IN
根据子查询位置
一组操作的集合,不可分割,要么同时成功,要么同时失败。——事务会把所有的操作作为一个整体一起向系统提交或撤销操作
默认MySQL的事务是自动提交的,也就是当执行一条DML语句,MySQL会立即隐式地提交事务
方式一:修改事务的提交方式
# 查看/设置事务提交方式
SELECT @@autocommit; # 查看当前事务的提交方式
SET @@autocommit=0; # 0表示手动提交;1表示自动提交
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;
# 无论正确执行还是错误执行,提交了之后就不能回滚回去了;只要没提交就能回滚。
# 一般执行没问题就提交,执行出错就回滚。
方式二:手动开启事务
# 开启事务
START TRANSACTION 或 BEGIN;
# 提交事务
COMMIT;
# 回滚事务
ROLLBACK;
-- ---------------------------- 事务操作 ----------------------------
-- 数据准备
create table account(
id int auto_increment primary key comment '主键ID',
name varchar(10) comment '姓名',
money int comment '余额'
) comment '账户表';
insert into account(id, name, money) VALUES (null,'张三',2000),(null,'李四',2000);
-- 恢复数据
update account set money = 2000 where name = '张三' or name = '李四';
#
#
select @@autocommit;
#
set @@autocommit = 0; -- 设置为手动提交
-- 转账操作 (张三给李四转账1000)
-- 1. 查询张三账户余额
select * from account where name = '张三';
-- 2. 将张三账户余额-1000
update account set money = money - 1000 where name = '张三';
... # 不知道这里为什么加.就会程序出错,希望以后学完回来能补充起来
-- 3. 将李四账户余额+1000
update account set money = money + 1000 where name = '李四';
-- 提交事务
commit;
-- 回滚事务
rollback ;
-- 方式二
-- 转账操作 (张三给李四转账1000)
start transaction ;
-- 1. 查询张三账户余额
select * from account where name = '张三';
-- 2. 将张三账户余额-1000
update account set money = money - 1000 where name = '张三';
程序执行报错 ...
-- 3. 将李四账户余额+1000
update account set money = money + 1000 where name = '李四';
-- 提交事务
commit;
-- 回滚事务
rollback;
事务的四大特性:
问题:
解决并发事务问题
级别分类:
# 查看事务隔离级别
SELECT @@TRANSACTION_ISOLATION;
# 设置事务隔离级别
SET [SESSION|GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE};
数据隔离级别越高,数据越安全,性能越低。