1. mysql简介
MySQL是一个关系型数据库管理系统
由瑞典MySQL AB 公司开发,属于 Oracle 旗下产品
Mysql是一个开源免费的关系型数据库管理系统
mysql分为社区办和企业版
我们学习的是社区版
2. 关系型数据库
建立在关系模型基础上的数据库,借助数学中的集合代数等一些数学概念和方法,处理关系型数据库中的数据
3. Mysql的安装
- windows的安装
- Linux的安装
4. Mysql默认的字符集的配置(了解)
以windows中的mysql的配置为例:
找到mysql的存放配置文件的地方
C:\ProgramData\MySQL\MySQL Server 5.6/my.ini
修改
1
2[mysqld]
character-set-server=utf8
但是: 我们完全不建议这样修改,因为我们每个项目系统使用的数据库编码完全有可能不一样;
5. 启动和停止mysql的服务
1 | net start mysql |
注意: 如果命令显式不可用代表操作系统的版本不支持(家庭版)
6. mysql的登录命令
1 | mysql -u用户名 -p密码 |
7. mysql常用的系统命令
1 | 查看mysql的版本 |
8. mysql的语句规范
- 关键字和函数名建议大写
- 数据库的名称,表的名称,字段的名称建议小写
- 数据库 表名 字段名建议加上``
- sql语句的定界符默认以; 结尾
9. 数据库的操作SQL类型(了解)
DDL(数据定义语言)(Data Defination Language)
1
2CREATE TABLE/VIEW/INDEX;
DROP DATABASE;DML(数据操纵语言)(Data Manipulation Language)
1
2
31) 插入:INSERT
2) 更新:UPDATE
3) 删除:DELETEDQL(数据查询语言)(Data Query Language)
1
2
3
4
5DQL基本结构是由SELECT子句,FROM子句,WHERE
子句组成的查询块:
SELECT <字段名表>
FROM <表或视图名>
WHERE <查询条件>
DCL(数据控制语言)(Data Control Language)
1
2用来定义安全级别和访问权限的
常用的关键字:grant revoke
10. mysql中的概念
- 数据库管理系统: 管理数据库的系统
- 数据库: 数组库是用来存放和组织
表
的 - 表:是存储数据的容器
- 记录: 一行的数据
- 属性: 一列属性值
11. 数据库的操作(必会)
- 创建数据库
1 | CREATE DATABASE `db2`; #最简单的方式创建一个数据库 |
注意: 数据库的名称可以加 `` ,也可以不加,默认mysql会给你自动加上
1 | CREATE DATABASE db2; #可以省略`` |
- 带判断的创建数据库
1 | CREATE DATABASE IF NOT EXISTS `db1`; #如果不存在db1这个数据库则创建db1数据库,如果存在则不会创建但是也不会报错 |
- 创建数据库并且指定字符集
1 | #mysql默认的字符集是latin1,latin1不支持中文 |
- 删除数据库
1 | #删除数据库,如果数据库不存在则会报错 |
- 查询数据库
1 | #查询数据库的创建信息 |
- 进入数据库
1 | USE 'db1'; |
12. mysql中的数据类型
12.1 整型
类型 | 范围 | 备注 |
---|---|---|
tinyint | 1个字节 范围(-128 |
与java中的byte类型对应 |
smallint | 2个字节 范围(-32768~32767|| 0 ~ 65535(无符号)) | 与java中的short对应 |
mediumint | 3 个字节, -8388608 to 8388607||0 to 16777215(无符号) | |
int:Integer | 4 个字节, -2147483648 to 2147483647||0 to 4294967295(无符号) | 与Java中的int类型对应 |
bigint | 8 个字节, -9223372036854775808 to 922337203685477580||0 to 18446744073709551615(无符号) | 与java中的long对应 |
12.2 浮点型
类型 | 范围 | 备注 |
---|---|---|
float(m,d) | 单精度浮点型 8位精度(4字节) m总个数,d小数位 | 与java的float对应 |
double(m,d) | 双精度浮点型 16位精度(8字节) m总个数,d小数位 | 与java的double对应 |
注意: 在实际开发过程中设计数据库时==一定一定一定==,涉及到小数的不要使用FLOAT和DOUBLE类型
12.3 定点
浮点型在数据库中存放的是近似值,而定点类型在数据库中存放的是精确值
类型 | 范围 | 备注 |
---|---|---|
decimal(m,d) | 参数m<65 是总个数,d<30且 d<m 是小数位 | 表示金额等精确值 |
注意: Decimal这个类型如果Insert的数据比我们预设的d的长度大,也会进行四舍五入; 一般存储小数都会使用DECIMAL类型,不会丢失精度
12.4 字符串
类型 | 范围 | 备注 |
---|---|---|
char(n) | 固定长度,最多255个 | 定长字符串,n 范围(0,255), 如果不是定长的数据,n<=4 时才使用 |
varchar(n) | 变长字符串,最多65532个字节 | 变长字符串,65532>n>4, 注意,n 是字符数,而不是字节数 |
tinytext | 存储 L+1 个字节,其中 L < 2^8 | |
text | 存储 L+2 个字节,其中 L < 2^16 | 存储文本的 |
mediumtext | 存储 L+3 个字节,其中 L < 2^24 | |
longtext | 存储 L+4 个字节,其中 L < 2^32 |
12.5 Blob二进制类型
BLOB 和 text 存储方式不同,TEXT 以文本方式存储,英文存储区分大小写,而 Blob 是以二进制方式存储,不分大小写。
BLOB 存储的数据只能整体读出。
TEXT 可以指定字符集,BLOB 不用指定字符集。
12.6 日期时间类型
类型 | 备注 |
---|---|
date | 日期 ‘2008-12-2’ |
time | 时间 ‘12:25:36’ |
datetime | 日期时间 ‘2008-12-2 22:06:44’ |
timestamp | 自动存储记录修改时间 |
13. mysql 中数据类型属性(约束-CONSTRAINT)
MySQL关键字 | 含义 | 备注 |
---|---|---|
NULL | 数据列可包含NULL值 | mysql默认不指定约束,字段也不添加值,默认为NULL |
NOT NULL | 数据列不允许包含NULL值 | 非空约束 |
DEFAULT | 默认值 | 默认值约束 |
PRIMARY KEY | 主键 | 主键约束 = 非空约束+唯一约束 |
AUTO_INCREMENT | 自动递增,适用于整数类型 | 自增(一般和数值类型的主键联合使用) |
UNSIGNED | 无符号 | 保留正数部分 |
UNIQUE | 唯一约束 | 此字段的值不能重复 |
作用
- 保证用户输入的数据存储到数据库中是正确的,准确的。
- 可以防止一些可能的输入错误。
- 如何使用完整性来保证存储到数据库中的数据是正确的准确的,需要在创建表的时候给表添加约束
分类
- 实体完整性
- 域完整性
- 引用完整性
14. 表的操作
数据表是数据库的最重要的组成部分之一,是其他对象的基础;
14.1 查看数据库中的所有的表
1 | SHOW TABLES; |
14.2 创建表
1 | CREATE TABLE `user`(id int,name char(32),age tinyint); |
1 | -- 带条件的创建表 |
1 | -- 创建表时指定字符集,如果不指定默认使用的是数据库的字符集 |
1 | -- 查看表结构 |
14.3 删除表
1 | -- 删除表 |
1 | -- 带判断的删除 |
14.4 修改表结构
1 | -- 添加列 |
1 | -- 删除列 |
1 | -- 查询列 |
1 | -- MODIFY只能修改列的属性 不能修改名字 |
15. 记录(数据)的操作
15.1 添加数据
1 | -- 给表插入一条数据 |
1 | -- 批量插入数据 |
1 | -- 骚操作(不指定字段全量插入)---->一般不建议使用全量插入数据 |
15.2 查询数据(简单查询)
1 | -- 最简单的查询语句 |
1 | -- 查询指定的字段 |
15.3 修改数据
1 | -- 修改数据 |
15.4 删除数据
1 | -- 删除数据 |
16. 表和表之间关系
16.1 一对一的关系
例如: 一个会员表中的一条记录只对应我们身份证表中的一条记录
我们如果设计数据库时出现了一对一的表应该尽量避免;我们只需要给字段多的一方的表添加额外的字段即可
如果我们设计的时候**无法避免(考虑的优化为题)**一对一的设计,我们需要让两个表的主键进行对应
如果一个表中的字段的个数超过16个,强烈建议使用一对一的表的设计
16.2 一对多的关系
例如: 一个会员对应多个订单,而一个订单只对应一个会员(会员表和订单表)
子表:订单表
在多的一方的表(订单表)加一个字段对应一的一方的表中的主键,数据类型要保持一致
而且我们根据墨菲定律,还可以为其加一个约束条件(外键(FOREIGN KEY))
1 | -- 在表创建之后添加外键 |
1 | -- 创建表的时候直接添加外键 |
注意:
- 创建一对多的表的时候,首先要创建一方对应的那个表
REFERENCES
:指定外键依赖的表及对应的列,并且该列为该表的主键- 我们为了数据的安全性,我们会把多方中的参照的字段设置为外键,而且类型要和一方中的主键保持一致
- 一般我们在商业项目中,尽量不要使用外键(等会解释)
16.3 多对多的关系
思想: 借助一个额外的表,实现多对多关系
1 | -- 创建商品表 |
17. mysql 的多字段查询
select * 这种方式不建议使用,我们只查询需要的字段,select * 这种方式对性能有影响
1 | -- 查询多个字段 |
1 | -- 查询字段并且指定字段的别名 |
1 | -- 这才是一条完整的sql语句,我们在实际的开发中不会写这个多的东西,会省略一些东西(库名,字段的别名,表的别名...),sql的执行引擎会帮我们进行词法和语法的补全 |
18. mysql 中的排序
ORDER BY col_name ASC|DESC
1 | -- 不指定任何的排序字段的情况下,默认是按主键的升序排列的 |
1 | -- 指定按age来排序(默认是升序) |
1 | -- 指定按age的降序进行排序 |
19. mysql中的分组查询
1 | -- 创建学生表 |
1 | -- 查询grade字段不为NULL的总记录数 |
1 | -- 查询年龄age>25的,班级及其班级里面的人数 WHERE 是对分组之前的数据进行筛选 |
1 | -- 查询年龄age>25的,班级人数>1的,班级及其班级里面的人数 |
20. mysql中的分页查询
1 | limit |
21. 查询小结
基本查询语句的书写顺序和执行顺序
书写顺序:
select-from-where-group by-having-order by-limit;
select-distinct-from-join-on-where-group by-having-order by-limit;
执行顺序:
from-where-group by-having-select-order by-limit;
from-on-join-where-group by-having-select-distinct-order by-limit;
22. AND 和 OR
1 | -- and代表两个添加都成立 |
1 | -- or其中只要有一个成立则查出来 |
23. IN和NOT IN
1 | -- 多个OR连接并不是很方便 |
1 | -- 多个AND连接不方便 |
24. BETWEEN…AND
1 | -- 查询指定区域内的数据 |
23. NOT BETWEEN…AND
1 | SELECT * FROM member WHERE age<30 OR age>40; |
26. mysql的子查询
把一个查询的结果当成另一个查询的条件进行使用
1 | -- 查询小花购买过的全部的商品 |
27. 多表查询
合并结果集
去重:union
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16CREATE TABLE aa(
id INT,
NAME VARCHAR(10)
);
INSERT INTO aa VALUES(1,'aaa');
INSERT INTO aa VALUES(2,'bbb');
INSERT INTO aa VALUES(3,'ccc');
CREATE TABLE bb(
id INT,
NAME VARCHAR(10)
);
INSERT INTO bb VALUES(1,'aaa');
INSERT INTO bb VALUES(2,'bbb');
INSERT INTO bb VALUES(4,'ddd');
SELECT * FROM aa UNION SELECT * FROM bb;不去重:union all
1
SELECT * FROM aa UNION ALL SELECT * FROM bb;
多表连接查询
使用关联关系可以去除无用笛卡尔积
内连接(显式内连接)
1
2
3
4
5
6
7
8
9
10-- 查询小花下过的订单(使用多表连接进行查询) 笛卡尔积
SELECT
member.id m_id,
member.nick_name,
orders.`address`,
orders.`create_time`
FROM
member INNER JOIN orders
ON member.id = orders.m_id
WHERE member.nick_name = '小花' ;注意:我们使用内连接的时候可以省略
INNER JOIN
,使用逗号
在多个表之间进行连接(隐式连接),连接条件也要使用WHERE
关键系代替ON
关键字隐式连接的语法不太友好,简单的多个表之间的查询可以使用,但是复杂的sql就不建议使用
隐式连接
1
2
3
4
5
6
7
8
9
10
11-- 查询小花下过的订单(使用多表连接进行查询) 笛卡尔积
SELECT
m.id m_id,
m.nick_name,
o.`address`,
o.`create_time`
FROM
member m,
orders o
WHERE m.id = o.m_id
AND m.nick_name = '小花' ;外链接 outer join on
左外连接 left outer join
特点:查询的结果存在不满足条件等式的可能性。
以左边的表为主表,先查询左表中的所有内容,然后再查询右表,右表满足条件的显示,不满足条件的显示为null。
1
2
3
4
5
6
7
8
9SELECT
member.id m_id,
member.nick_name,
orders.`address`,
orders.`create_time`
FROM
member LEFT JOIN orders
ON member.id = orders.m_id
AND member.nick_name = '小花' ;右外连接 right outer join(不建议使用,因为可以直接转换为左外链接)
自然链接 natural join
链接查询会产生笛卡尔积,可以使用主外键关系等式去除笛卡尔积。自然链接,我们不需要自己给出主外键关系等式,它会自己找到。自动拿2个表中名字和类型一样的列作为条件。
1
2
3SELECT * FROM emp NATURAL JOIN dept;
SELECT * FROM emp NATURAL LEFT JOIN dept;
SELECT * FROM emp NATURAL RIGHT JOIN dept;
28. 多表的连接的商业项目使用建议
- 多表连接时尽量使用显式连接,因为显式连接的 sql 的语义明确
- 生产环境建议表的联查个数不要超过 3 张表(可以是3张)
- 如果 3 张表的联查还不能解决你的问题,那么你就需要在业务层面解决或者是数据库设计缺陷
- 在项目中不建议使用外键,我们完全可以在业务层保证数据的安全性
- 数据库本质的作用是用来存储数据,而不是进行数据约束的;因为外键会造成我们数据源库迁移的灾难;
29. 级联删除与级联更新
外键的级联删除:如果父表中的记录被删除,则子表中对应的记录自动被删除
父表——被外键引用的表
子表——引用父表中的主键作为外键的表
1 | -- ON DELETE CASCADE 级联删除 |
1 | -- ON UPDATE CASCADE 级联更新 |
当然级联更新和级联删除时可以同时设置的
1 | ALTER TABLE orders ADD FOREIGN KEY (`m_id`) REFERENCES member (`id`) |
也可以借助可视化工具进行修改级联删除和级联更新
30. mysql中的分隔符(定界符)
mysql中默认的分割符是 ;
也就是说遇到 ;
就会立即执行sql
在函数存储过程这些特性中需要写多个sql组成一个整体,当成整体来执行,而这些特性中,一条一条的语句之间语法规定必须用;
来分开
所以我们要创建函数 存储过程 必须先要把默认的分隔符 ;
替换成其他的符号;
在会话中替换默认的分隔符,使用下面语句
1 | DELIMITER $$ |
31. mysql中的函数
函数:在编程中函数其实就是一段业务的封装
mysql中的函数: 对多个sql业务的封装,避免反复的进行词法和语法分析
31.1 系统函数
mysql系统帮我们定义的函数
1 | -- 查询mysql系统当前时间 |
31.2 聚合函数
1 | -- 统计某个字段的记录数 |
31.3 数学函数
数学函数主要用于处理数字,包括整型、浮点数等。
31.4 字符串函数
字符串函数是MySQL中最常用的一类函数,字符串函数主要用于处理表中的字符串。
31.5 日期时间函数
MySQL的日期和时间函数主要用于处理日期时间。
31.6 条件判断函数
条件判断函数用来在 SQL 语句中进行条件判断。根据是否满足判断条件,SQL 语句执行不同的分支。例如,从员工表中查询员工的业绩。如果业绩高于指定值 n,则输出 good;否则,输出 bad。下面是各种条件判断函数的表达式、作用和使用方法。
IF(expr,v1,v2)函数
IF(expr,vl,v2)函数中,如果表达式expr成立,返回结果v1;否则,返回结果v2。
IFNULL(v1,v2)函数
IFNULL(v1,v2)函数中,如果v1的值不为空,就显示v1的值;否则就显示v2的值。
CASE函数
CASE WHEN expr1 THEN v1 [WHEN expr2 THEN v2…] [ELSE vn] END
CASE WHEN exprl THEN v1 [WHEN expr2 THEN v2…] [ELSE vn] END函数中,CASE表示函数开始,END表示函数结束。如果表达式expr1成立时,返回v1的值。如果表达式expr2成立时,返回v2的值。依次类推,最后遇到ELSE时,返回vn 的值。
CASE expr WHEN e1 THEN v1 [WHEN e2 THEN v2…] [ELSE vn] END
CASE expr WHEN e1 THEN v1 [WHEN e2 THEN v2…] [ELSE vn] END 函数中,如果表达式expr取值等于e1时,返回v1的值。如果表达式expr取值等于e2时,返回v2的值。依次类推,最后遇到ELSE时,返回vn的值。CASE表示函数开始,END表示函数结束。
31.7 自定义函数(了解)
我们自己编写的函数
- 函数的参数
- 返回值
1 | - 函数的可以返回任意类型的值,也可以接受任意类型的值为参数 |
1 | CREATE FUNCTION 函数名称(参数名称 参数类型) RETURNS 返回值类型 |
1 | -- 首先创建函数之前一定要先修改其定界符,要不然遇到函数中的第一个;就会执行报错 |
1 | -- 创建自定义函数 |
函数的调用
1 | SELECT 函数名称(实参列表); |
删除函数
1 | DROP FUNCTION [IF EXISTS] `MYADD` |
自定义函数可能出现错误:
1 | 错误代码: 1418 |
原因:mysql在新版本中添加函数保护器,默认如果不进行配置,则无法创建自定义函数,我们需要在当前会话中把函数保护器关掉,尽量不要在全局(系统的配置文件)关闭函数保护器;
1 | -- 查看函数保护器的状态 |
1 | -- 允许创建自定义函数 |
经过上面的设置我们就可以正常的创建自定义函数了;
32. mysql存储过程(了解)
32.1 sql语句的执行流程
1 | sql语句--->sql执行优化器(编译)--->词法分析,语法分析--->sql优化--->运行sql(读取数据)-->结果 |
32.2 什么是存储过程?
sql 语句的编译的集合,以名称来存储,合并为一个单元处理;
如果在实现用户的某些需求时,需要编写一组复杂的 SQL 语句才能实现的时候,那么我们就可以将这组复杂的 SQL 语句集提前编写在数据库中,由 JDBC 调用来执行这组 SQL 语句。
把编写在数据库中的 SQL 语句集称为存储过程。
存储过程就类似于 Java 中的方法,需要先定义,使用时需要调用。存储过程可以定义参数,参数分为 IN、OUT、INOUT
类型三种类型。
- IN 类型的参数表示接受调用者传入的数据;
- OUT 类型的参数表示向调用者返回数据;
- INOUT 类型的参数即可以接受调用者传入的参数,也可以向调用者返回数据。
32.3 存储过程的特点
优点
- 实现较快的执行速度(避免重复的编译,词法分析,语法分析等操作)
- 减少网络流量,减少应用程序和数据库服务器之间的流量。
- 存储的程序是安全的。数据库管理员是可以向访问数据库中存储过程的应用程序授予适当的权限,而不是向基础数据库表提供任何权限。
- 简化对变动的管理。如果表名、列名、或业务逻辑有了变化。只需要更改存储过程的代码。使用它的人不用更改自己的代码。
缺点
- 如果使用大量的存储过程,那么使用这些存储过程的每个连接的内存使用量将大大增加。此外,如果在存储过程中过度使用大量的逻辑操作,那么 CPU 的使用率也在增加,因为 MySQL 数据库最初的设计就侧重于高效的查询,而不是逻辑运算。
- 存储过程的构造使得开发具有了复杂的业务逻辑的存储过程变得困难。
- 很难调试存储过程。只有少数数据库管理系统允许调试存储过程。不幸的是,MySQL 不提供调试存储过程的功能。
- 开发和维护存储过程都不容易。开发和维护存储过程通常需要一个不是所有应用程序开发人员拥有的专业技能。这可能导致应用程序开发和维护阶段的问题。
- 对数据库依赖程度较高,移值性差。
32.4 存储过程的语法
1 | -- 创建存储过程 |
32.5 删除存储过程
1 | DROP PROCEDURE proc1; |
33. mysql函数和存储过程对比
存储过程和函数都是为了提高程序的运行效率和减少网络带宽而存在的
存储过程可以实现相对复杂的功能,而函数针对性比较强
存储过程可以返回多个值(无需
return
关键字),函数只能有一个返回值在实际商业项目中尽量不要使用存储过程和自定义函数
34. mysql中的视图(了解)
视图其实就是一个虚拟表,这虚拟表可以存储我们查询的结果,方便我们进行二次查询,提升查询效率;查询的时候就可以像使用表一样用视图
1 | -- 创建视图(View) |
1 | -- 查询视图的数据(可以把视图当成表来使用) |
1 | -- 删除视图 |
注意: 视图是依赖表而存在的,如果表被删除了,视图就无效了;
35. mysql 中的触发器(了解)
触发器(trigger):监听事件,并触发某操作
触发器的四要素:
- 监视地点(table)
- 监视事件(insert/update/delete)
- 触发时机(after/before)
- 触发事件(insert/update/delete)
1 | -- 创建班级表 |
需求: 我们删除班级,实现自动删除班级对应的学生
1 | -- 创建触发器 |
36. mysql 中的存储引擎
mysql 可以将数据以不同的技术存储在文件或者(内存)中,这种技术叫存储引擎;
每种存储引擎都有不同的存储机制,索引技术,表锁定技术,最终应用的场景各不相同,但是现在最主流的 mysql 的存储引擎用的对多的还是INNODB
1 | -- 查询数据库支持哪些存储引擎 |
存储引擎 | MYISAM | INNODB | MEMORY |
---|---|---|---|
存储限制 | 256TB | 64TB | 有限制 |
事务安全性 | NO | YES | NO |
支持索引 | YES | YES | YES |
数据压缩 | YES | NO | NO |
是否支持外键 | NO | YES | NO |
如果没有特殊要求,在互联网项目中,INNODB存储引擎是我们首选;
37. 执行mysql的脚本
登录mysql之后执行sql脚本
1
source sqlpath
登录mysql时候直接执行sql脚本
1
mysql -uroot -p <sqlpath
使用可视化工具备份和还原(推荐做法)
38. Mysql管理工具
- Workbench(mysql官方推荐使用的) 免费的 跨平台的
- Sequel Pro 只在mac端有
- HeidiSQL(免费 开源)
- phpMyAdmin(web应用)
- mysqlfont(免费 轻量级) 只有windows端有,对高分辨率屏支持不好
- Navicat(商业 收费) 跨平台 功能最强大 UI最漂亮
- SQLyog(收费 不跨平台) 对高分辨率屏支持不好
39. mysql的版本升级
升级数据库版本之前一定要先备份数据,再执行升级;
- 备份数据
- 卸载老版本的mysql
- 停止系统的mysql服务
- 检查系统服务是否存在如果存在先删除
sc delete mysql
,这个命令必须使用管理员用户权限 - 删除数据目录
- 安装新版本的
mysql-8.0.22.0
- 恢复数据(执行前面备份的sql脚本)
40. mysql中的模糊查询
%
: 匹配0个或者多个任意字符
_
: 匹配任意一个字符
1 | -- 查询昵称中以 '小' 开头的数据 |
- 模糊查询的前缀查询效率
极低
(要进行全表扫描),要慎重使用; - 一般生产环境会直接禁用 like 模糊查询功能;
- 左模糊查询(“%abc”)不会使用索引
- 右模糊查询(“abc%”)会使用索引 abc
41. mysql 中的事务
41.1 mysql 事务介绍
事务是一个最小的不可再分的工作单元,把做完一个业务分成好多单元,整个过程每个单元全部处理成功,才算整个的业务处理成功,只要有任何一个单元处理失败,则认为业务处理失败;
作用: 保证了数据的完整性
属性:传播行为、隔离级别、只读和事务超时
41.2 事务控制
整个过程的每一个单元全部处理成功那么事务才会提交(commit),只要其中任何一个单元出现异常,则让事务回滚(rollback)
41.3 事务的特性
ACID
atomicity(原子性): 事务中所有的操作要么全部成功,要么全部失败;
consistency(一致性): 事务执行前后的状态(数据)保持一致
isolation(隔离性): 多个事务在执行过程中互相不受影响
durability(持久性): 事务一旦被提交,那么对数据库中的数据的改变时永久性的,即使在数据库系统遇到故障的时候,排除故障之后这些数据也不会丢失;
注意: 只有当前三条性质都满足了,才能保证事务的一致性;事务这个特性其实我们一直在使用,只是我们没有特别的在意这个事,因为mysql默认的事务的提交方式是自动提交的
1 | SHOW VARIABLES LIKE "%autocommit%" |
41.4 手动控制事务的提交与回滚
mysql 默认事务的提交方式是自动提交的,但是我们一般使用到事务的时候都会进行手动的控制,也就是要关闭mysql的事务自动提交;
1 | -- 开启事务(临时关闭mysql的"事务自动提交") |
1 | -- 开启事务(临时关闭mysql的"事务自动提交") |
41.5 事务的隔离性
隔离性保证了多个事务在执行过程中互相不受影响;
mysql 中的事务隔离级别有以下几种:
- Read UNCOMMITTED(读未提交)
- READ COMMITTED(读已提交) —->oracle中事务默认的隔离级别
- REPEATABLE READ(重复读) —>mysql中的事务的隔离级别
- SERIALIZABLE(串行化)
1 | -- 查询默认的事务隔离级别 |
1 | -- 更改当前会话的隔离级别 |
41.6 事务隔离级别引发的问题
脏读问题
脏读: 设置事务的隔离级别为
READ UNCOMMITTED
,会读到其他事务没有提交的数据;例如:事务 A 读取到了事务已经修改但未提交的数据,这种数据就叫脏数据,是不正确的
解决脏读: 设置事务的隔离级别为
READ COMMITTED
,可以解决数据脏读问题
不可重复读问题
不可重复读: 在一个事务中,前后两次读到的数据不一致
例如:对于事务A多次读取同一个数据时,由于其他是事务也在访问这个数据,进行修改且提交,对于事务A,读取同一个数据时,有可能导致数据不一致,叫不可重复读。
解决不可重复读: 使用的
REPEATABLE READ
隔离级别可以解决;
虚读|幻读问题
虚读: 设置为
READ UNCOMMITTED, READ COMMITTED, REPEATABLE READ
的事务,有时候可以读取到其他事务新插入的行,这种情况就称为虚读;解决虚读: 把事务的隔离级别设置成
SERIALIZABLE
之后就可以解决虚读问题;
解决方案: 我们在实际开发过程中一般不会使用两个极端的隔离级别(读未提交, 串行化),我们会使用中间的两个;
41.7 事务的传播特性
PROPAGATION_REQUIRED–支持当前事务,如果当前没有事务,就新建一个事务。这是最常见的选择。
PROPAGATION_SUPPORTS–支持当前事务,如果当前没有事务,就以非事务方式执行。
PROPAGATION_MANDATORY–支持当前事务,如果当前没有事务,就抛出异常。
PROPAGATION_REQUIRES_NEW–新建事务,如果当前存在事务,把当前事务挂起。
PROPAGATION_NOT_SUPPORTED–以非事务方式执行操作,如果当前存在事务,就把当前事务挂起。
PROPAGATION_NEVER–以非事务方式执行,如果当前存在事务,则抛出异常。
42. innodb 锁机制
42.1 innodb锁机制介绍
从锁的颗粒来说锁分为行锁和表锁;
在 innodb 中提供了两种锁机制:
乐观锁: 并不是硬编码的实现,而是通过 version 版本号来进行实现(innodb 中并没有实现乐观锁)
悲观锁: 这是 innodb 存储引擎默认实现的锁机制,这种锁是表锁,而悲观锁的实现又分为两种实现:
共享锁(S锁),读锁
在读取的行设置一个共享模式的锁,这个共享锁允许其他的会话读取数据,但是不允许修改,如果其他的会话也需要修改数据,则要等待持有共享锁的会话结束锁的释放,才能修改数据
可以在多个会话中加多个共享锁
添加多个共享锁容易出现互相等待释放的情况,造成死锁问题,所以使用多个共享锁一定要慎重,
排它锁(X锁),写锁
- 排它锁是不允许重复添加的
排它锁没有死锁问题
42.2 显式加锁
- 共享锁的添加:
lock in share mode
- 排它锁的添加:
for update
1 | select * from account lock in share mode; |
42.3 mvcc 并发系统快照读与当前读
快照读: 不加锁的 select 操作就属于快照读
当前读: 加锁的操作属于当前读
当前读读到的是最新的数据,而且在读取的过程中是不允许其他的事务修改数据;
43. mysql中的执行计划
mysql 执行流程:
客户端(sql语句)—>mysql-rdbms–>innodb存储引擎–>sql查询优化器(sql语句的优化)—>….
sql 查询优化器会把优化的东西形成一个产物,这个产物就是执行计划; 简单来说就是 SQL 在数据库中执行时的表现情况。
我们在实际的开发过程中,一般涉及到mysql的优化都会先查看其执行计划;
1 | EXPLAIN SELECT * FROM shop; |
- 执行计划看的时候先看执行计划的 id,id越大的先执行;
- 如果 id 相同从上往下看
44. mysql 中的索引技术(非常重要)
44.1 索引技术的介绍
- mysql 中的索引技术可以帮助我们快速检索数据
- innodb 底层索引技术就是通过B+tree实现的
- 索引其实就是我们平常用到的 ‘
目录
‘ - 索引在 mysql 启动时就会加到内存中,形成 B+Tree,在 mysql 停止的时候会持久化到硬盘;
44.2 索引的分类
- 普通索引
- 主键索引
- 唯一索引
- 全文索引
44.3 普通索引
普通索引如果不指定名称,则索引的名称和字段的名称相同;
1 | -- 创建索引的第一种方式 |
- 建立普通索引的列的数据是可以重复的
44.4 主键索引
主键索引如果不指定索引的名称,则主键索引的名称为 PRIMARY
1 | -- 声明为主键的列就是自动添加主键索引 |
主键索引的列的数据非空,唯一的
一个表中建议只有一个主键列
44.5 唯一索引
唯一索引如果不指定名称,则索引的名称和字段的名称相同;
1 | -- 创建索引的第一种方式 |
- 如果一列被约束为
UNIQUE
,则在这一列默认添加唯一索引 - 添加唯一索引的列可以为
NULL
值,这也是和主键索引,不同的地方
44.6 全文索引
全文索引,通过建立
倒排索引
,可以提高数据的检索效率,解决判断字段中是否包含
的问题;
我们如果使用 like 关键字会出现很多问题:
1 | -- 我们已经给nickname字段添加了普通索引 |
不使用到索引我们如果进行大规模数据检索时,效率会大大的降低,所以前面我们说过 我们只在简单业务或者数据量小的时候才考虑使用like关键字
;
全文索引注意的地方:
mysql5.6以前,只有
MYISAM
存储引擎支持全文索引在5.6中
INNODB
存储引擎加入了对全文索引的支持,但是只支持英文的全文索引,不支持中文的全文索引在5.7.6中,mysql 内置了
ngram
分词器,用来支持中文;
配置 ngram 分词的最小长度:
默认长度为2,当然我们也可以设置成1,但是设置成1的话就会浪费大量的空间,不是很好,mysql建议我们配置为2
;
1 | ngram分词器对分词最小长度(也就是说分词器,分词的时候最小也是两个词一分) |
创建全文索引
1 | -- 创建索引的第一种方式 |
使用全文索引
1 | SELECT * FROM account WHERE MATCH(nickname) AGAINST("你觉得华为笔记本合小米手机哪个好"); |
match
中的字段和创建全文建索引时的字段必须一致;
全文索引的检索流程
用户输入词—>sql 执行引擎—>ngram
分词器对用户输入的词进行分词(配置了最小的分词个数)—>把分词器分的词依次的去倒排索引中去查找,找出相应的记录返回;
44.7 组合索引
包含多个字段的索引称为组合索引;
组合索引包含
- 组合普通索引
- 组合主键索引
- 组合唯一索引
- 组合全文索引
1 | -- 创建复合索引时必须指定索引的名称,不能省略 |
1 | SELECT * FROM article WHERE title LIKE '小米%'; -- 使用到索引 |
建议多列索引的列不要超过2个列
以上这个复合索引相当于建立了这3个索引
1
(title),(title,content),(title,content,publish_time)
多列索引遵循最左前缀的原则
多列索引在创建的时候,如果其中有字段时
TEXT
或BLOB
类型,就必须指定索引的长度;
44.8 使用索引的优点
- 使用主键索引或者唯一索引,可以保证数据库中的表的数据是唯一
- 通过建立索引可以大大的提高数据检索的效率,减少表扫描的行数(避免进行全表扫描)
- 我们在进行多表连接的时候,可以使用索引加速表之间的连接
44.9 使用索引的缺点
- 在创建索引和维护索引时都需要耗费时间;
- 索引文件会占用物理存储空间,除了表的数据占用一部分空间,索引文件也会占用一部分空间;
- 设置为
text
和blob
类型的字段强烈不建议添加索引;
45. mysql中的记录截取
1 | SELECT * FROM account LIMIT start,count; |
46. mysql 数据库设计(了解)
第一设计范式 :表中的每一列都不能再分(不要出现二维表)
第二设计范式:满足第一设计范式,除主键外每一列都必须依靠主键
第三设计范式:满足第二设计范式,除主键列外,每一列都不能相互依靠
数据库范式的提出是很早以前的事了,在很早以前硬盘是非常昂贵的,一般都会遵循 1,2,3 范式,但是随着互联网的发展,硬盘非常便宜,所以我们在现在的商业项目中一般不会遵循 2,3 范式(用时间换空间),第一范式会遵循;
47. 国内大厂的数据库开发规范(参照阿里的开发规范)
库名与应用名称尽量一致
表名、字段名必须使用小写字母或数字,禁止出现数字开头,如果一个单词不能表达那就使用下划线分隔;
表名不使用复数名词;
表的命名最好是加上“业务名称_表的作用”。如,edu_teacher
表必备三字段:id, gmt_create, gmt_modified
说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增、步长为 1。(如果使用分库分表集群部署,则id类型为varchar,非自增,业务中使用分布式id生成器)
gmt_create, gmt_modified 的类型均为 datetime 类型,前者现在时表示主动创建,后者过去分词表示被动更新。单表行数超过 500 万行或者单表容量超过 2GB,才推荐进行分库分表。 说明:如果预计三年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
表达是与否概念的字段,必须使用 is_xxx 的方式命名,数据类型是 unsigned tinyint (1 表示是,0 表示否)。
说明:任何字段如果为非负数,必须是 unsigned。
注意:POJO 类中的任何布尔类型的变量,都不要加 is 前缀。数据库表示是与否的值,使用 tinyint 类型,坚持 is_xxx 的 命名方式是为了明确其取值含义与取值范围。
正例:表达逻辑删除的字段名 is_deleted,1 表示删除,0 表示未删除。小数类型为 decimal,禁止使用 float 和 double。 说明:float 和 double 在存储的时候,存在精度损失的问题,很可能在值的比较时,得到不 正确的结果。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
varchar 是可变长字符串,不预先分配存储空间,长度不要超过 5000,如果存储长度大于此值,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其它字段索 引效率。
唯一索引名为 uk_字段名;普通索引名则为 idx_字段名。
说明:uk_ 即 unique key;idx_ 即 index 的简称不得使用外键与级联,一切外键概念必须在应用层解决。外键与级联更新适用于单机低并发,不适合分布式、高并发集群;级联更新是强阻塞,存在数据库更新风暴的风险;外键影响数据库的插入速度
慎重使用
like
进行模糊查询, 通配符如果在前面则不会使用到索引,影响检索效率;如果是简单的搜索业务建议使用mysql5.7中新增的全文索引,不建议直接上solor,elasticsearch这样的检索系统,因为会使得维护成本增加;