You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

90 lines
6.2 KiB
Markdown

# MySQL 高级
## 1. 系统是怎么和 MySQL 打交道 ?
- MySQL不仅仅是CRUD
### 1.1 MySQL 驱动
- mysql 驱动是跟数据库进行的一个网络连接建立工具
- 不同的语言有不同的驱动使用
### 1.2 数据库连接池
- 作用是减少连接的重复建立和销毁让线程去执行SQL语句后, 不要销毁这个数据库连接,而是放在池子中进行复用
- 常见的数据库连接池有: DBCPC3P0Druid
## 2. 执行 SQL 语句, MySQL用了什么架构设计
- 一个不变的原则: 网络连接必须让线程来处理
![MySQL架构设计](pic/MySQL架构设计.png)
- SQL 接口: 负责处理接收到的SQL语句
- 监听请求以及读取请求数据的线程, 把解析好的SQL语句v转交给SQL接口去执行
- 查询解析器: 按照估计的SQL语法, 对我们发送的 SQL 语句进行解析, 理解其要进行的操作
- 查询优化器: 生成查询路径树, 然后从里面选择一条最优的查询路径
- 调用存储引擎, 真正的执行 SQL 语句
- MySQL 的设计架构中, SQL接口, SQL解析器, 查询优化器其实都是通用的,就是一套组件
- 存储引擎可以供我们去选择, 选择那种存储引擎来执行SQL。常见的存储引擎: InnoDB, MyISAM, Memory等。
- 执行器: 执行器会根据我们的优化器生成一套执行计划, 然后不停的调用存储引擎的各种接口去完成SQL语句的执行计划
## 3. 用一次数据更新流程, 了解 InnoDB 引擎的架构设计
### 3.1 InnoDB 的重要内存结构: 缓冲池
![缓冲池](pic/缓冲池.png)
- InnoDB 的很重要放在内存里面的组件, 里面会缓冲很多数据, 在查询时候, 如果查的是内存中的数据, 就不用去查盘了
![缓冲池加载](pic/缓冲池加载.png)
- 引擎在更新语句的时候, 比如 "id=10" 这行数据是否在缓冲池中, 如果不在就从磁盘中加载到缓冲池, 而且还会对这行数据加独占锁
### 3.2 undo日志文件: 如何让你更新的数据可以回滚?
![undo日志](pic/undo日志.png)
- 我们开发中可以轻松地利用事务对数据提交的过程进行回滚操作是因为会把更新前的值写入到undo日志文件中
### 3.3 更新 buffer pool 中的缓存数据
- 当我们要把更新的那行记录从磁盘文件加载到缓冲池, 同时对他加锁, 而且还把更新前的旧值写入undo日志文件之后, 我们才正式开始更新
这行记录, 更新的时候, 先会更新缓冲池中的记录, 此时这个数据是脏数据
- 这里所谓的更新内存缓冲池里的数据, 意思是把内存里的 "id=10" 这行数据的name修改为 "xxx"
- 为什么说是脏数据呢?
- 因为这个时候磁盘上 "id=10" 这行数据的name字段还是以前的值, 但是内存里面这行数据已经改变了, 所以称为脏数据
![更新buffer-pool中的缓存数据](pic/更新bufferpool中的缓存数据.png)
### 3.4 Redo Log Buffer: 万一系统宕机, 如何避免数据丢失?
- 在 3.3 中如果此时宕机, 会导致内存中改过的数据丢失, 怎么办?
- 这个时候,就必须把对内存的修改写到一个Redo Log Buffer 中, 这也是内存里的一个缓冲区, 是用来存放 redo 日志的
- 所谓 redo 日志,就是记录你对数据做了什么修改, 比如对 "id=10这行记录修改了name字段的值为xxx", 这就是一个日志
![redo日志](pic/redo日志.png)
- 这个 redo 日志其实是用来在 MySQL 突然宕机的时候, 用来恢复你更新过的数据, 现在redo日志还仅仅停留在内存缓冲里
### 3.5 如果还没提交事务, MySQL 宕机了怎么办?
- 执行一条SQL语句, 其实也可以是一个独立的事务, 当你提交事务后, SQL语句才算执行结束
- 此时还没有提交事务, 如果此时 MySQL 崩溃, 必然导致内存里 Buffer Pool 中的修改过的数据都丢失,
同时你写入 Redo Log Buffer 中的redo日志也会丢失<br/>
![没提交事务宕机](pic/没提交事务宕机.png)
- 此时, 丢数据不要紧, 因为你一条更新语句, 没提交事务, 就代表他没执行成功, 磁盘上的数据没有改变, mysql 重启后, 你的数据无任何变化
### 3.6 提交事务的时候将redo日志写入磁盘中
- 我们提交一个事务, 此时会根据一定的策略把redo日志从 redo log buffer里刷入到磁盘文件里去
- 这个策略是通过 innodb_flush_log_at_trx_commit 来配置的
- 当这个值为0时候, 你提交事务的时候,不会把redo log buffer里面的数据刷入磁盘文件,此时可能你都提交事务了, 结果MySQL宕机了, 然后此时内存里的数据全部丢失
相当于你提交事务成功了, 但是由于MySQL突然宕机, 导致内存中的数据和redo日志都丢失了<br/>
![redo写磁盘0](pic/redo写磁盘0.png)
- 当这个参数值为1的时候, 你提交事务的时候, 就必须把redo log从内存刷入到磁盘文件中去, 只要事务提交成功, 那么redo log就必然在磁盘里了
![redo写磁盘1](pic/redo写磁盘1.png)
- 只要提交事务成功, redo日志一定在磁盘文件中了, 此时你肯定会有一条redo日志说了, "我对什么数据进行了一个什么操作"
- 然后哪怕此时buffer pool中更新过的数据还没刷到磁盘里面去,此时内存中的数据是已经更新过的"name=xxx",然后磁盘上的数据是还没更新过的"name=zhangsan"
![redo写磁盘3](pic/redo写磁盘3.png)
- 此时不会丢数据, 因为redo日志中已经记录了操作
- 所以此时mysql重启后, 可以根据redo日志去恢复之前做的修改
![redo写磁盘4](pic/redo写磁盘4.png)
- 如果 innodb_flush_log_at_trx_commit 值为2
- 意思是说, 提交事务的时候, 把redo日志写入磁盘文件对应的os cache缓存里去, 而不是直接进入磁盘文件, 可能1秒后才会把 os cache 里的数据写入到磁盘文件中去
- 这种模式下,你提交了事务, redo log可能仅仅停留在os cache内存缓存中, 没实际进入磁盘文件, 万一此时你要是机器宕机了, 那么os cache里的redo log就会丢失
同样让你感觉提交了事务, 数据丢了
![redo写磁盘5](pic/redo写磁盘5.png)
---
- 总结: 对于redo日志的三种刷盘策略, 我们的通常建议是1, 保证事务提交后, 数据绝对不能丢失
## 4. 聊聊binlog是什么?