数据类型
- tinyint/smallint/int/bigint
- float
- double
- char/varchar
- date/time/datetime/timestamp
DDL
数据库
create database db1;
create database if not exists db2;
create database db3 charset gbk;
-- 查看所有的数据库
show databases;
-- 查看某个数据库的定义信息
show create database db1;
-- 修改字符集改成utf8,注:不是utf-8,是utf8
alter database db3 character set utf8;
drop database 库名;-- 删除
-- 查看正在使用的数据库
select database(); -- 是一个函数
-- 使用db1数据库
use db1;
表
-- 创建表
create table 表名(
列名 数据类型(长度) 约束,
列名 数据类型(长度) 约束,
....
)
-- 查看某个数据库中的所有表
show tables;
-- 查看表结构
desc 表名;
-- 查看创建表的SQL语句,看到的是mysql生成的语句,并不是我们写的,功能是一样的。
show create table 表名;
-- 复制表结构,没有其中记录
-- 语法:create table 新表 like 旧表
修改表 修改表,添加列
alter table 表名 add 列名 数据类型(长度)
修改表,修改列的数据类型
alter table 表名 modify 列名 数据类型(长度)
修改表,删除列
alter table 表名 drop 列名
删除表
drop table [if exists] 表名;
DML
1. 插入数据(新增数据)
insert into 表名 (列名1,列名2...) values(值1,值2...); //自增主键值可以为null;
2. 更新数据
update 表名 set 列名1=值1, 列名2=值2 [where 条件]
3. 删除数据
delete from 表名 [where 条件]
DQL
select
字段列表
from
表名
where
条件(where子句)
group by
分组字段
having
分组后的过条件
order by
排序条件
limit
分页限定
执行顺序from >> where >> group by >> having >> select >> order by >> limit
聚合函数查询 count(列名) 统计个数,一般我们会写 count(*)
max(列名) 最大值
min(列名) 最小值
avg(列名) 平均值
sum(列名) 求和
注意:聚合函数会自动排除NULL值
order by 列名 排序方式,列名2 排序方式2
ASC:升序,默认值
DESC: 降序
group by 分组字段
分组查询查询的字段一般为分组字段和聚合函数
where是在分组进行过滤, having是在分组后对数据进行过滤。
where后面不能跟聚合函数条件,聚合函数条件只能跟在having关键字后
limit 起始记录, 每页查询的记录数
多表查询
内连接查询
隐式内连接
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 条件;
子查询
将一条查询语句作为一张虚拟表
Mysql约束
约束 | 作用 |
---|---|
PRIMARY KEY | 主键约束 |
PRIMARY KEY AUTO_INCREMENT | 主键自增 |
UNIQUE | 唯一约束 |
NOT NULL | 非空约束 |
FOREIGN KEY | 外键约束 |
FOREIGN KEY ON UPDATE CASCADE | 外键级联更新 |
FOREIGN KEY ON DELETE CASCADE | 外键级联删除 |
主键约束
特点:主键约束默认包含非空和唯一两个功能。
一张表只能有一个主键。
主键一般用于表中数据的唯一标识。
建表时添加主键约束
CREATE TABLE 表名(
列名 数据类型 PRIMARY KEY,
...
列名 数据类型 约束
);
删除主键约束
ALTER TABLE 表名 DROP PRIMARY KEY;
建表后单独添加主键约束
ALTER TABLE 表名 MODIFY 列名 数据类型 PRIMARY KEY;
主键自增约束
建表时添加主键自增约束
CREATE TABLE 表名(
列名 数据类型 PRIMARY KEY AUTO_INCREMENT,
...
列名 数据类型 约束
);
删除主键自增约束
ALTER TABLE 表名 MODIFY 列名 数据类型;
建表后单独添加主键自增约束
ALTER TABLE 表名 MODIFY 列名 数据类型 AUTO_INCREMENT;
唯一约束
建表时添加唯一约束
CREATE TABLE 表名(
列名 数据类型 UNIQUE,
...
列名 数据类型 约束
);
删除唯一约束
ALTER TABLE 表名 DROP INDEX 列名;
建表后单独添加唯一约束
ALTER TABLE 表名 MODIFY 列名 数据类型 UNIQUE;
外键约束
建表时添加外键约束
CREATE TABLE 表名(
列名 数据类型 约束,
...
CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主表主键列名)
);
删除外键约束
ALTER TABLE 表名 DROP FOREIGN KEY 外键名;
建表后单独添加外键约束
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);
外键的级联更新和级联删除
同时添加级联更新和级联删除
ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名)ON UPDATE CASCADE ON DELETE CASCADE;
视图
视图:是一种虚拟存在的数据表,这个虚拟表并不在数据库中实际存在。
作用:将一些较为复杂的查询语句的结果,封装到一个虚拟表中,后期再有相同需求时,直接查询该虚拟表即可。(实则存储的是一条sql语句)
创建视图语法
CREATE VIEW 视图名称 [(列名列表)] AS 查询语句;
查询视图语法
SELECT * FROM 视图名称;
修改视图数据语法
UPDATE 视图名称 SET 列名=值 WHERE 条件;
修改视图结构语法
ALTER VIEW 视图名称 (列名列表) AS 查询语句;
删除视图语法
DROP VIEW [IF EXISTS] 视图名称;
存储过程
创建存储过程
-- 修改结束分隔符
DELIMITER $
-- 创建存储过程
CREATE PROCEDURE 存储过程名称(参数列表)
BEGIN
SQL 语句列表;
END$
-- 修改结束分隔符
DELIMITER ;
调用存储过程
CALL 存储过程名称(实际参数);
查看数据库中所有的存储过程
SELECT * FROM mysql.proc WHERE db='数据库名称';
删除存储过程
DROP PROCEDURE [IF EXISTS] 存储过程名称;
存储过程语法 - 变量
定义变量
DECLARE 变量名 数据类型 [DEFAULT 默认值];
变量赋值方式一
SET 变量名 = 变量值;
变量赋值方式二
SELECT 列名 INTO 变量名 FROM 表名 [WHERE 条件];
存储过程语法 – if 语句
IF 判断条件1 THEN 执行的sql语句1;
[ELSEIF 判断条件2 THEN 执行的sql语句2;]
...
[ELSE 执行的sql语句n;]
END IF;
存储过程语法 - 参数传递
CREATE PROCEDURE 存储过程名称([IN|OUT|INOUT] 参数名 数据类型)
BEGIN
SQL 语句列表;
END$
IN:代表输入参数,需要由调用者传递实际数据(默认)
OUT:代表输出参数,该参数可以作为返回值
INOUT:代表既可以作为输入参数,也可以作为输出参数
存储过程语法 – while 循环
初始化语句;
WHILE 条件判断语句 DO
循环体语句;
条件控制语句;
END WHILE;
存储函数
创建存储函数
CREATE FUNCTION 函数名称(参数列表)
RETURNS 返回值类型
BEGIN
SQL 语句列表;
RETURN 结果;
END$
调用存储函数
SELECT 函数名称(实际参数);
删除存储函数
DROP FUNCTION 函数名称;
触发器
触发器是与表有关的数据库对象,可以在 insert、update、delete 之前或之后触发并执行触发器中定义的 SQL 语句。这种特性可以协助应用系统在数据库端确保数据的完整性、日志记录、数据校验等操作。使用别名 NEW 和 OLD 来引用触发器中发生变化的内容记录。
触发器分类
触发器类型 | OLD | NEW |
---|---|---|
INSERT 型触发器 | 无 (因为插入前无数据) | NEW表示将要或者已经新增的数据 |
UPDATE 型触发器 | OLD表示修改之前的数据 | NEW表示将要或已经修改后的数据 |
DELETE 型触发器 | OLD 表示将要或者已经删除的数据 | 无 (因为删除后状态无数据) |
创建触发器
DELIMITER $
CREATE TRIGGER 触发器名称
BEFORE|AFTER INSERT|UPDATE|DELETE
ON 表名
FOR EACH ROW
BEGIN
触发器要执行的功能;
END$
DELIMITER ;
查看触发器
SHOW TRIGGERS;
删除触发器
DROP TRIGGER 触发器名称;
事务
事务的四大特征(ACID)
-
原子性(Atomicity)
原子性是指事务包含的所有操作要么全部成功,要么全部失败回滚。
因此事务的操作如果成功就必须要完全应用到数据库,如果操作失败则不能对数据库有任何影响。 -
一致性(Consistency)
一致性是指事务必须使数据库从一个一致性状态变换到另一个一致性状态。
也就是说一个事务执行之前和执行之后都必须处于一致性状态。 -
隔离性(isolcation)
隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务。
不能被其他事务的操作所干扰,多个并发事务之间要相互隔离。 -
持久性(durability)
持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的。
即便是在数据库系统遇到故障的情况下也不会丢失提交事务的操作
事务的隔离级别
隔离级别 | 名称 | 会引发的问题 |
---|---|---|
read uncommitted | 读未提交 | 脏读、不可重复读、幻读 |
read committed | 读已提交 | 不可重复读、幻读 |
repeatable read | 可重复读 | 幻读 |
serializable | 串行化 | 无 |
引发的问题
问题 | 现象 |
---|---|
脏读 | 在一个事务处理过程中读取到了另一个未提交事务中的数据,导致两次查询结果不一致 |
不可重复读 | 在一个事务处理过程中读取到了另一个事务中修改并已提交的数据,导致两次查询结果不一致 |
幻读 | 查询某数据不存在,准备插入此记录,但执行插入时发现此记录已存在,无法插入。或查询数据不存在执行删除操作,却发现删除成功 |
存储引擎
- MySQL 支持的存储引擎有很多,常用的有三种:InnoDB、MyISAM、MEMORY。
- MyISAM 存储引擎:访问快,不支持事务和外键操作。使用场景:以查询操作为主,只有很少的更新和删除操作,并且对事务的完整性、并发性要求不是很高!
- InnoDB 存储引擎:支持事务和外键操作,支持并发控制,占用磁盘空间大。(MySQL 5.5版本后默认) 使用场景:对事务的完整性有比较高的要求,在并发条件下要求数据的一致性,读写频繁的操作!
- MEMORY 存储引擎:内存存储,速度快,不安全。适合小量快速访问的数据。使用场景:通常用于更新不太频繁的小表,用来快速得到访问的结果!
创建数据表,指定存储引擎
CREATE TABLE 表名(
列名,数据类型,
...
)ENGINE = 引擎名称;
查询某个数据库中某个数据表的存储引擎
SHOW TABLE STATUS FROM 数据库名称 WHERE NAME = '数据表名称';
修改数据表的存储引擎
ALTER TABLE 表名 ENGINE = 引擎名称;
索引
按照功能分类
-
普通索引:最基本的索引,没有任何限制。
-
唯一索引:索引列的值必须唯一,但允许有空值。如果是组合索引,则列值组合必须唯一。
-
主键索引:一种特殊的唯一索引,不允许有空值。在建表时有主键列同时创建主键索引。
-
联合索引:顾名思义,就是将单列索引进行组合。
-
外键索引:只有 InnoDB 引擎支持外键索引,用来保证数据的一致性、完整性和实现级联操作。
-
全文索引:快速匹配全部文档的方式。InnoDB 引擎 5.6 版本后才支持全文索引。MEMORY 引擎不支持。
按照结构分类
-
BTree 索引:MySQL 使用最频繁的一个索引数据结构,是 InnoDB 和 MyISAM 存储引擎默认的索引类型,底层基于 B+Tree 数据结构。
-
Hash 索引:MySQL 中 Memory 存储引擎默认支持的索引类型。
创建索引
CREATE [ UNIQUE | FULLTEXT ] INDEX 索引名称
[USING 索引类型] -- 默认是BTREE
ON 表名(列名...);
查看索引
SHOW INDEX FROM 表名;
添加索引
普通索引:ALTER TABLE 表名 ADD INDEX 索引名称(列名);
组合索引:ALTER TABLE 表名 ADD INDEX 索引名称(列名1,列名2,...);
主键索引:ALTER TABLE 表名 ADD PRIMARY KEY(主键列名);
外键索引:ALTER TABLE 表名 ADD CONSTRAINT 外键名 FOREIGN KEY (本表外键列名) REFERENCES 主表名(主键列名);
唯一索引:ALTER TABLE 表名 ADD UNIQUE 索引名称(列名);
全文索引:ALTER TABLE 表名 ADD FULLTEXT 索引名称(列名);
删除索引
DROP INDEX 索引名称 ON 表名;
索引的原理 – 磁盘存储
-
系统从磁盘读取数据到内存时是以磁盘块(block)为基本单位的。
-
位于同一个磁盘块中的数据会被一次性读取出来,而不是需要什么取什么。
-
InnoDB 存储引擎中有页(Page)的概念,页是其磁盘管理的最小单位。InnoDB 存储引擎中默认每个页的大小为 16KB。
-
InnoDB 引擎将若干个地址连接磁盘块,以此来达到页的大小 16KB,在查询数据时如果一个页中的每条数据都能有助于定位数据记录的位置,这将会减少磁盘 I/O 次数,提高查询效率。
索引的原理 – B+Tree
-
BTree 数据结构
每个节点中不仅包含 key 值,还有数据。会增加查询数据时磁盘的 IO 次数。 -
B+Tree 数据结构
非叶子节点只存储 key 值。
所有数据存储在叶子节点。
所有叶子节点之间都有连接指针。 -
B+Tree 好处
提高查询速度。
减少磁盘的 IO 次数。
树型结构较小。
索引的设计原则
创建索引遵循的原则
- 对查询频次较高,且数据量比较大的表建立索引。
- 使用唯一索引,区分度越高,使用索引的效率越高。
- 索引字段的选择,最佳候选列应当从 where 子句的条件中提取。
- 索引虽然可以有效的提升查询数据的效率,但并不是多多益善。
最左匹配原则(适用组合索引)
例如:为 user 表中的 name、address、phone 列添加组合索引
ALTER TABLE user ADD INDEX idx_three(name,address,phone);
此时,组合索引 idx_three 实际建立了 (name)、(name,address)、(name,address,phone) 三个索引
下面的三个 SQL 语句都可以命中索引
SELECT * FROM user WHERE address = '北京' AND phone = '12345' AND name = '张三';
SELECT * FROM user WHERE name = '张三' AND address = '北京';
SELECT * FROM user WHERE name = '张三';
这三条 SQL 语句在检索时分别会使用以下索引进行数据匹配
(name,address,phone)
(name,address)
(name)
索引字段出现的顺序可以是任意的,MySQL 优化器会帮我们自动的调整 where 条件中的顺序
如果组合索引中最左边的列不在查询条件中,则不会命中索引
SELECT * FROM user WHERE address = '北京';
InnoDB和MyISAM存储数据和索引上的区别
-
innodb是将数据和索引存储在.ibd文件中的
-
myisam是将索引存储在.myi文件中,将数据存储在.myd文件中,先去myi文件中找到数据的磁盘地址,再去myd文件中根据地址直接获取数据。
MySQL锁机制
锁机制 : 数据库为了保证数据的一致性,在共享的资源被并发访问时变得安全所设计的一种规则。
锁机制类似多线程中的同步,作用就是可以保证数据的一致性和安全性。
按操作分类
-
共享锁:也叫读锁。针对同一份数据,多个事务读取操作可以同时加锁而不互相影响 ,但是不能修改数据。
-
排他锁:也叫写锁。当前的操作没有完成前,会阻断其他操作的读取和写入。
按粒度分类
-
表级锁:会锁定整个表。开销小,加锁快。锁定力度大,发生锁冲突概率高,并发度低。不会出现死锁情况。
-
行级锁:会锁定当前行。开销大,加锁慢。锁定粒度小,发生锁冲突概率低,并发度高。会出现死锁情况。
按使用方式分类
-
悲观锁:每次查询数据时都认为别人会修改,很悲观,所以查询时加锁。
-
乐观锁:每次查询数据时都认为别人不会修改,很乐观,但是更新时会判断一下在此期间别人有没有去更新这个数据。
不同存储引擎支持的锁
存储引擎 | 表锁 | 行锁 |
---|---|---|
InnoDB | 支持 | 支持 |
MyISAM | 支持 | 不支持 |
MEMORY | 支持 | 不支持 |
InnoDB 共享锁
-
共享锁特点:数据可以被多个事务查询,但是不能修改。
-
创建共享锁格式:SELECT语句 LOCK IN SHARE MODE;
InnoDB 排他锁
- 排他锁特点:加锁的数据,不能被其他事务加锁查询或修改。
- 创建排他锁格式:SELECT语句 FOR UPDATE;
MyISAM 读锁
- 读锁特点,所有连接只能查询数据,不能修改。
- 读锁语法格式 加锁:LOCK TABLE 表名 READ; 解锁:UNLOCK TABLES;
MyISAM 写锁
-
写锁特点,其他连接不能查询和修改数据。
-
写锁语法格式 加锁:LOCK TABLE 表名 WRITE; 解锁:UNLOCK TABLES;
悲观锁和乐观锁
-
悲观锁它对于数据被外界修改的操作持保守态度,认为数据随时会修改。
整个数据处理中需要将数据加锁。悲观锁一般都是依靠关系型数据库提供的锁机制。 -
乐观锁每次自己操作数据的时候认为没有人会来修改它,所以不去加锁。
但是在更新的时候会去判断在此期间数据有没有被修改。
需要用户自己去实现,不会发生并发抢占资源,只有在提交操作的时候检查是否违反数据完整性。
方式一:给数据表中添加一个 version 列,每次更新后都将这个列的值加 1。
读取数据时,将版本号读取出来,在执行更新的时候,比较版本号。
如果相同则执行更新,如果不相同,说明此条数据已经发生了变化。
用户自行根据这个通知来决定怎么处理,比如重新开始一遍,或者放弃本次更新。
方式二:和版本号方式基本一样,给数据表中添加一个列,名称无所谓,数据类型需要是 timestamp。
每次更新后都将最新时间插入到此列。
读取数据时,将时间读取出来,在执行更新的时候,比较时间。
如果相同则执行更新,如果不相同,说明此条数据已经发生了变化。
行锁和表锁
- InnoDB的行锁是针对索引加的锁,不是针对记录加的锁。并且该索引不能失效,否则都会从行锁升级为表锁。行锁的劣势:开销大;加锁慢;会出现死锁行锁的优势:锁的粒度小,发生锁冲突的概率低;处理并发的能力强
- 加锁的方式:自动加锁。对于UPDATE、DELETE和INSERT语句中使用到索引列,InnoDB会自动给涉及数据集加排他锁;对于普通SELECT语句,InnoDB不会加任何锁;当然也可以显示的加锁;