数据库
首页 > 数据库> > 学习最新大厂付费视频时整理的万字长文+配图带你搞懂 MySQL

学习最新大厂付费视频时整理的万字长文+配图带你搞懂 MySQL

作者:互联网

万字长文+配图带你搞懂 MySQL

MySQL

SQL的介绍

SQL(Structured Query Language):结构化查询语言。其实就是定义了操作所有关系型数据库的一种规则。通用语法规则
SQL语句可以单行或多行书写,以分号结尾可使用空格和缩进来增强语句的可读性
MySQL数据库的SQL语句不区分大小写,关键字建议使用大写

单行注释:

-- 注释内容
# 注释内容(MySQL特有)

多行注释︰

/* 注释内容 */

SQL分类

MySQL语法

创建数据库

修改、删除、使用数据库

DDL查询数据表

t_user为demo数据库中的一个表,含义为用户表。带自己的表命名标准 t_ 前缀。

DDL创建数据表

修改数据表结构

删除数据表

DML添加数据

列名和值的数量以及数据类型要对应,除了数字类型,其他数据类型的数据都需要加引号(单引双引都行)

DML修改表里的数据

DML删除表里的数据

DQL表数据查询

查询语句结构

第一行的select from 是最基本的,后面的是可选的

select 字段列表 from 表名列表

where 条件列表

group by 分组字段

having 分组后的过滤条件

order by 排序字段列表

limit 分页

查询全部数据

-- select * from 表名
select * from t_user;

查询指定字段的数据

-- select 列名1,列名2,... from 表名
select name,age from t_user;

去除重复查询 distinct

-- select distinct 字段列表 from 表名
select distinct name,age from t_user;

计算列的值(四则运算、函数比如sum)

-- select 列名1 运算符(+-*/) 列名2 from 表名
-- 查询出所有人年龄的和
select sum(age) from t_user;

对查询结果起别名

-- select 列名 as 别名  from 表名;
-- 这样查询出的结果里就会是 age_sum
select sum(age) as age_sum from t_user;

查询可使用的条件

在这里插入图片描述

查询可使用的聚合函数

聚合函数语法

select 函数名(列名) from 表名 [where 条件可选];

示范查询用户表有多少条记录

select count(id) from t_user;

在这里插入图片描述

查询结果排序

排序语法

排序方式asc升序,desc降序,可不写,默认升序

如果写了多个排序条件,则先按第一个排序,当第一个列值相同,则继续用第二个排序,以此类推

select 列名列表 from 表名 [where 条件可选] order by 列名 排序方式,列名 排序方式

示范

select * from t_user where age > 0 order by age desc;
select * from t_user where age > 0 order by age desc,id asc;

分组查询

分组查询语法

select 列名列表 from 表名 [where条件] group by 分组列名 [having分组后的条件过滤] [orderby 排序列名排序方式];

select * from t_user group by age;
select * from t_user group by age having age >= 18;
select * from t_user group by age having age >= 18 order by age desc;

分页查询

分页查询语法

select 列名列表 from 表名 [where条件] group by 分组列名 [having分组后的条件过滤] [orderby 排序列名排序方式] limit 从第多少条开始,要的条数;

从多少条开始计算公式=(页码-1)*页数

约束

约束主要是对表中的数据进行限定,保证数据的正确性、有效性、完整性。

一般在创建数据表的时候会定义好约束
在这里插入图片描述

主键约束primary key
唯一约束 unique
非空约束 not null
外键约束 foreign key

外键约束不建议使用,尤其是级联删除

多表操作

起别名

关键字 as

t_user as u 就是给t_user起了个别名为u

-- 从t_user(别名u)和t_order隐式内连接查询出订单表中uid等于用户表的id的
select * from t_user as u,t_order as o where u.id = o.uid;

内连接查询

交集部分

外连接查询

全部数据+交集数据

-- select 列名 from 表名1 left [outer] join 表名2 on 条件;
select * from t_user left outer join t_order on t_user.id = t_order.uid;
-- select 列名 from 表名1 right [outer] join 表名2 on 条件;
select * from t_user right outer join t_order on t_user.id = t_order.uid;

全连接查询

全部数据

-- select 列名 from 表名1,表名2;
select * from t_user,t_order;

子查询

  1. 结果是单行数据(可以看做是一个值)

    • 查询年级最大的用户姓名
    select name from t_user where age = (select max(age) from t_user);
    
  2. 结果是多行单列的(可以看做是一个数组)

    • 查询年龄小于18岁的用户的订单记录
    select * from t_order where uid in (select id from t_user where age < 18);
    
  3. 查询结果是多行多列的(可以看做是一个虚拟表)

    • 查询年龄小于18岁的用户的信息和他们的订单记录
    select * from t_order as o,(select * from t_user where age < 18) as u where o.uid = u.id;
    
  4. 自关联查询(自己和自己连接)

    • 查询自己的信息和自己的上级信息(没有上级的也要显示,其实就是左外连接)
    create table employ(
        id int auto_increment primary key,
        name varchar(12),
        -- 上级领导的ID
        leadedId int
    );
    
    select e1.id as id,e1.name as name,e1.leaderId as leaderId,e2.name as leaderName from employ as e1 left out join employ as e2 on e1.leaderId = e2.id ;
    

视图

将你书写的查询语句查询出的结果封装成一个虚拟的数据表,这个表并不实际存在,而是在你查询这个表的时候会先去执行你之前写的查询语句,把结果作为一个表来使用。

创建视图

create table city(
	id int primary key,
    name varchar(24),
    countryId int comment '国家ID'
)comment '城市表';
create table country(
	id int primary key,
    name varchar(24)
)comment '国家表';
-- create view 视图名 [(列名...)] as 查询语句
-- 可选项 列名列表,会和查询结果一一对应
create view city_country (city_id,city_name,country_name) as select c1.id,c1.name,c2.name from city c1,country c2 where c1.countryId = c2.id;
-- city_id |  city_name | country_name
   1          上海           中国

查询视图

可以看做是一个表来使用

修改视图数据

源表中相关数据也会随之修改!

删除视图

存储过程和函数

其实就是提前写好的一些SQL语句的集合,提高复用性。

存储过程

存储函数

必须有返回值,和存储过程很类似。

触发器

在某个操作被执行的时候触发另一个操作

触发器介绍

触发器分类

在这里插入图片描述

创建触发器

delimiter $
create trigger 触发器名称
before|after insert|update|delete
on 表名
for each row
begin
	触发器要执行的功能
end$
delimiter ;
delimiter $
create trigger trigger_demo
after insert
on t_user
for each row
begin
	insert into t_user_log (operation,operation_time,operation_id,operation_data) values('insert',now(),new.id,concat('插入后:{id=',new.id,',username=',new.username,'}'))
end$
delimiter ;
delimiter $
create trigger trigger_demo
after update
on t_user
for each row
begin
	insert into t_user_log (operation,operation_time,operation_id,operation_data) values('update',now(),old.id,concat('更新前:{id=',old.id,',username=',old.username,'}更新后{id=',new.id,',username=',new.username,'}'))
end$
delimiter ;
delimiter $
create trigger trigger_demo
after delete
on t_user
for each row
begin
	insert into t_user_log (operation,operation_time,operation_id,operation_data) values('delete',now(),old.id,concat('删除前:{id=',old.id,',username=',old.username,'}'))
end$
delimiter ;

查看触发器

show triggers;

删除触发器

-- drop trigger 触发器名称;
drop trigger trigger_demo;

事务

事务介绍

MySQL 事务主要用于处理操作量大,复杂度高的数据。比如说,在人员管理系统中,你删除一个人员,你既需要删除人员的基本资料,也要删除和该人员相关的信息,如信箱,文章等等,这样,这些数据库操作语句就构成一个事务!

事务ACID四原则

一般来说,事务是必须满足4个条件(ACID)::原子性(Atomicity,或称不可分割性)、一致性(Consistency)、隔离性(Isolation,又称独立性)、持久性(Durability)。

事务Demo

张三给李四转账500元,需要对张三的账号余额减500,李四的账号余额加500。

-- 下面的命令不是全部直接执行,而是一条条自己去执行
-- 开启事务
start transaction;
-- 进行操作
update t_user set money = money - 500 where name = '张三';
update t_user set money = money + 500 where name = '李四';
-- 回滚事务(出错的时候去执行这个就能恢复到开始事务之前的状态,执行都成功你就别执行回滚了)
rollback;
-- 提交事务(自动提交的时候不需要)
commit;

事务提交方式(自动/手动)

事务隔离级别

多个客户端操作时,各个客户端的事务之间应该是隔离的,相互独立的,不受影响的。
而如果多个事务操作同一批数据时,就会产生不同的问题,我们需要设置不同的隔离级别来解决这些问题。

在这里插入图片描述

隔离级别 有四种,分别是:读未提交、读已提交、可重复读、序列化。

大多数数据库默认的事务隔离级别是 Read Committed,比如 SQL Server , Oracle。但 MySQL 的默认隔离级别是 Repeatable Read。

select @@tx_isolation;
-- 默认是 repeatable read
-- set global transaction isolation level 级别字符串;
set global transaction isolation level read committed;

脏读问题

需要设置事务隔离级别为read uncommited读未提交(允许读取其他事务未提交的修改了的数据) 才能复现

张三给李四转账,开启事务,给自己余额减去五百,给李四余额加五百,李四开启事务,查询自己余额是不是多了500,查到是的的确多了500,然后张三让李四给他打一个欠条,李四打完欠条后张三回滚了账号余额数据,而李四给张三打了500欠条,血亏。因此李四读到了张三事务进行中影响的数据造成了读取到了脏的数据。

脏读其实就是读到了别人事务正在修改的数据(未提交)

-- 事务1
start transaction;
-- 张三跟李四借钱,张三开始修改余额
update t_user set money = money - 500 where name = '张三';
update t_user set money = money + 500 where name = '李四';
-- 查到余额改变了,跟李四要欠条,然后回滚数据
select * from t_user;
rollback;
commit;
-- 事务2
start transaction;
-- 查看转账
select * from t_user;
-- 写借条
commit;

解决办法:将事务隔离界别上升到读已提交以上的级别,那么张三没有提交之前,李四这边查到的永远还是之前余额的数据,因此不会给张三收据,直到张三提交事务,李四才能查到自己的账号钱增加了

不可重复读问题

程序员拿着自己的卡去买东西,结账的时候,收银台开启事务,查询卡余额,有三万够支付的,而此时他妻子拿着手机打开了银行转账,开启事务,把所有钱转走,事务完成,现在程序员的卡里没有一分钱了,而收银台的事务读到的还是三万余额,等扣钱的时候发现没钱了。事务中两次对同一数据的读取结果不同,则产生了不可重复读问题。

-- 收银台开启事务1
start transaction;
-- 查卡余额三万
select * from t_user where name = "程序员";
--  ........
-- 程序员妻子转完账了,再查询余额的时候没钱了,无法扣款
commit;
-- 程序员妻子转账开启事务2
start transaction;
-- 查看转账
update t_user set money = money -30000 where name = '程序员';
commit;
-- 转账成功

解决办法:将事务隔离界别上升到可重复读以上的级别,可重复读以后呢,底层使用MVCC( Mutil-Version Concurrent Control(多版本并发控制)),让每个事务读取的时候查如果没有自己这个事务对这个数据查询的结果那就去查询并建立ReadView,如果有的话就返回之前读取的结果,因此在这个事务你可以重复多次读取仍然是第一次读取到的那个值。

幻读问题

你开启事务,查询手机号码为xx的账号是否注册了,你发现没有注册,你就准备插入这条用户记录,而你查询的时候,我也开启了事务,我往里面也插入这条记录,我提交了,而你提交的时候会报错,因为这条记录已经存在了。而你明明查询的时候这条记录没有,执行插入又有,就成了幻读。

解决办法:将事务隔离界别上升到串行化级别,每个事务依次执行完,执行完一个才能执行下一个。

存储引擎

在这里插入图片描述

常用存储引擎

数据库引擎操作

show engines;

在这里插入图片描述

-- show table status from 数据库名称;
-- 下面例子里就一个staff表
show table status from demo_db;

在这里插入图片描述

存储引擎的选择建议

总结∶针对不同的需求场景,来选择最适合的存储|擎即可!如果不确定、则使用数据库默认的存储引擎!

索引

索引介绍

在这里插入图片描述

索引分类

按照功能分类

按照结构分类

创建索引

-- create index 索引名称 on 表名称(列名);
create index inx_name on t_user(name);
-- create index 索引名称 on 表名称(列名);
create unique index inx_age on t_user(age);

查询索引

show index from t_user;

在这里插入图片描述

添加索引

(大小写都是一样的)

删除索引

-- drop index 索引名称 on 表名称;
drop index idx_name on t_user;

索引原理

BTree

例如查找id为15的数据,读取磁盘块1,15小于17,从c2指针找到左边磁盘块2,读取磁盘块2,15大于12通过c7找到右下边的磁盘块7,读取磁盘块7,然后从左往右,依次遍历13,15找到id为15的数据。因为每次都需要读取每个找的过程中遇到的节点,效率不够高,因此有B+Tree优化。

在这里插入图片描述

B+Tree

找id为15的数据,读取磁盘块1,id15小于id28,则通过c2指针读取磁盘块2,发现id15在id10和id17之间,通过c5指针找到磁盘块5,读取磁盘块5,从磁盘块5中找到id15的数据。由于所有数据放在最底层第三层的叶子节点中,前面两层全部存的id和指针,因此需要读取的少,不需要读取数据,减少了io次数,因此效率更高。

另外B+Tree将最底层每个磁盘块左右用指针连接起来,在范围查找的时候,只需要找范围的两端,然后利用左右指针即可找出这个范围的。

在这里插入图片描述

索引设计原则

  1. 对查询频次较高,且数据量比较大的表建立索引

  2. 使用唯一索引,区分度越高,使用索引的效率越高。

  3. 索引字段的选择,最佳候选列应当从where子句的条件中提取。

  4. 索引虽然可以有效的提升查询数据的效率,但并不是多多益善。

锁机制

锁的介绍

锁使用示范

InnoDB共享锁、排他锁
MyISAM读锁

悲观锁

前面的共享锁、排他锁就是悲观锁,先上锁,再操作。

悲观锁就是很悲观,它对于数据被外界修改的操作持保守态度,认为数据随时会修改。整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系型数据库提供的锁机制。我们之前所学的锁机制都是悲观锁。

乐观锁

乐观锁就是很乐观,每次自己操作数据的时候认为没有人会来修改它,所以不去加锁。但是在更新的时候会去判断在此期间数据有没有被修改。
需要用户自己去实现,不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性。

在这里插入图片描述

数据库备份和恢复

图形化操作自己用工具导出表结构和数据即可,此处只写命令方式。

备份到文件

# mysqldump -u 用户名 -p 数据库名 > 文件存储地址
# 下面例子使用root账户将demo_db这个数据库备份到/root/demo_db.sql这个文件中(数据表和数据都有)
mysqldump -u root -p demo_db > /root/demo_db.sql
# 回车后输入账号的密码回车

从文件中恢复数据库

# 进入mysql
mysql -u root -p
# 输入密码后回车(不会回显你输入的)
-- 查看所有数据库
show databases;
-- 如果数据库不存在,则先创建数据库
create database demo_db;
-- 切换到这个数据库
use demo_db
-- 加载执行sql文件,即可恢复之前的表和数据
source  /root/demo_db.sql

数值类型

MySQL支持所有标准SQL数值数据类型。

这些类型包括严格数值数据类型(INTEGER、SMALLINT、DECIMAL和NUMERIC),以及近似数值数据类型(FLOAT、REAL和DOUBLE PRECISION)。

关键字INT是INTEGER的同义词,关键字DEC是DECIMAL的同义词。

BIT数据类型保存位字段值,并且支持MyISAM、MEMORY、InnoDB和BDB表。

作为SQL标准的扩展,MySQL也支持整数类型TINYINT、MEDIUMINT和BIGINT。下面的表显示了需要的每个整数类型的存储和范围。

类型大小范围(有符号)范围(无符号)用途
TINYINT1 byte(-128,127)(0,255)小整数值
SMALLINT2 bytes(-32 768,32 767)(0,65 535)大整数值
MEDIUMINT3 bytes(-8 388 608,8 388 607)(0,16 777 215)大整数值
INT或INTEGER4 bytes(-2 147 483 648,2 147 483 647)(0,4 294 967 295)大整数值
BIGINT8 bytes(-9,223,372,036,854,775,808,9 223 372 036 854 775 807)(0,18 446 744 073 709 551 615)极大整数值
FLOAT4 bytes(-3.402 823 466 E+38,-1.175 494 351 E-38),0,(1.175 494 351 E-38,3.402 823 466 351 E+38)0,(1.175 494 351 E-38,3.402 823 466 E+38)单精度 浮点数值
DOUBLE8 bytes(-1.797 693 134 862 315 7 E+308,-2.225 073 858 507 201 4 E-308),0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)0,(2.225 073 858 507 201 4 E-308,1.797 693 134 862 315 7 E+308)双精度 浮点数值
DECIMAL对DECIMAL(M,D) ,如果M>D,为M+2否则为D+2依赖于M和D的值依赖于M和D的值小数值

日期和时间类型

表示时间值的日期和时间类型为DATETIME、DATE、TIMESTAMP、TIME和YEAR。

每个时间类型有一个有效值范围和一个"零"值,当指定不合法的MySQL不能表示的值时使用"零"值。

TIMESTAMP类型有专有的自动更新特性,将在后面描述。

类型大小 ( bytes)范围格式用途
DATE31000-01-01/9999-12-31YYYY-MM-DD日期值
TIME3‘-838:59:59’/‘838:59:59’HH:MM:SS时间值或持续时间
YEAR11901/2155YYYY年份值
DATETIME81000-01-01 00:00:00/9999-12-31 23:59:59YYYY-MM-DD HH:MM:SS混合日期和时间值
TIMESTAMP41970-01-01 00:00:00/2038结束时间是第 2147483647 秒,北京时间 2038-1-19 11:14:07,格林尼治时间 2038年1月19日 凌晨 03:14:07YYYYMMDD HHMMSS混合日期和时间值,时间戳

字符串类型

字符串类型指CHAR、VARCHAR、BINARY、VARBINARY、BLOB、TEXT、ENUM和SET。该节描述了这些类型如何工作以及如何在查询中使用这些类型。

类型大小用途
CHAR0-255 bytes定长字符串
VARCHAR0-65535 bytes变长字符串
TINYBLOB0-255 bytes不超过 255 个字符的二进制字符串
TINYTEXT0-255 bytes短文本字符串
BLOB0-65 535 bytes二进制形式的长文本数据
TEXT0-65 535 bytes长文本数据
MEDIUMBLOB0-16 777 215 bytes二进制形式的中等长度文本数据
MEDIUMTEXT0-16 777 215 bytes中等长度文本数据
LONGBLOB0-4 294 967 295 bytes二进制形式的极大文本数据
LONGTEXT0-4 294 967 295 bytes极大文本数据

注意:char(n) 和 varchar(n) 中括号中 n 代表字符的个数,并不代表字节个数,比如 CHAR(30) 就可以存储 30 个字符。

CHAR 和 VARCHAR 类型类似,但它们保存和检索的方式不同。它们的最大长度和是否尾部空格被保留等方面也不同。在存储或检索过程中不进行大小写转换。

BINARY 和 VARBINARY 类似于 CHAR 和 VARCHAR,不同的是它们包含二进制字符串而不要非二进制字符串。也就是说,它们包含字节字符串而不是字符字符串。这说明它们没有字符集,并且排序和比较基于列值字节的数值值。

BLOB 是一个二进制大对象,可以容纳可变数量的数据。有 4 种 BLOB 类型:TINYBLOB、BLOB、MEDIUMBLOB 和 LONGBLOB。它们区别在于可容纳存储范围不同。

有 4 种 TEXT 类型:TINYTEXT、TEXT、MEDIUMTEXT 和 LONGTEXT。对应的这 4 种 BLOB 类型,可存储的最大长度不同,可根据实际情况选择。

标签:--,列名,查询,user,MySQL,搞懂,配图,id,select
来源: https://blog.csdn.net/HumorChen99/article/details/119085799