文章目录
1 MySQL基础
1.1 关系型数据库
关系型数据库: 建立在关系模型上的数据库
表明了数据库中所存储的数据之间的联系(一对一,一对多,多对多)
数据被存储在各种表中,每张表的每一行存放一条数据
大部分关系型数据库都使用SQL语句来操作数据库中的数据
且大部分数据库都支持事务的四大特性ACID
1.2 MySQL介绍
MySQL: 一种关系型数据库,主要用于持久化存储系统中一些数据,如用户信息
是开源且免费较为成熟的数据库,默认端口号为3306
2 存储引擎
2.1 MySQL中的存储引擎
可以使用show engines;
来查看MySQL提供的所有存储引擎
可以看到MySQL默认使用的是InnoDB,且只有InnoDB引擎支持事务
2.2 MyISAM和InnoDB的区别
在MySQL5.5之前,MyISAM是默认的存储引擎,虽然MyISAM性能和特性尚可,但是MyISAM不支持行级锁和事务,且最大的缺陷是崩溃后无法恢复,在MySQL5.5之后,MySQL引入了InnoDB
MyISAM和InnoDB的区别:
1,是否支持行级锁
MyISAM只有表级锁
InnoDB支持行级锁和表级锁,默认为行级锁
即MyISAM一锁就是一张表,在并发的情况下性能很糟糕
而InnoDB的行级锁在并发时,有更好的性能
2,是否支持事务
MyISAM不支持事务
InnoDB提供事务支持,具有提交和回滚事务的能力
3,是否支持外键
MyISAM不支持外键
InnoDB支持外键
一般不建议在数据库层面使用外键,在应用层可以解决
4,是否支持数据库崩溃后的安全恢复
MyISAM不支持
InnoDB支持,使用InnoDB的数据库在异常崩溃后
数据库重新启动时会保证数据库恢复到崩溃前的状态,这个过程依赖于redo log(重做日志)
InnoDB通过使用redo log保证事务的持久性,使用undo log来保证事务的原子性
InnoDB引擎通过使用锁机制,MVCC等手段保证事务的隔离性
保证了事务的持久性,原子性,隔离性之后,一致性才能得到保障
5,是否支持MVCC
MVCC可以看作是行级锁的一个升级,可以有效减少加锁操作,提升性能
MyISAM不支持
InnoDB支持
3 锁机制和InnoDB锁算法
MyISAM使用表级锁
InnoDB支持行级锁和表级锁,默认使用行级锁
表级锁和行级锁对比:
表级锁: MySQL中粒度最大的锁,对当前整张表进行加锁,实现简单,资源消耗较少
加锁快,不会出现死锁,并发度最低
行级锁: MySQL中粒度最小的锁,只对当前操作的行加锁,行级锁能大大减少操作数据库的冲突
并发度高,单锁的开销也最大,加锁慢,可能会出现死锁
InnoDB锁的算法:
1,Record Lock: 记录锁,单个行上的锁
2,Gap Lock: 间隙锁,锁定一个范围,不包括行本身
3,Next-key Lock: 临键锁,锁定一个范围,包括行本身
4 查询缓存
执行查询语句时,会先查询缓存,不过这个功能在MySQL8.0之后被移除,因为不太常用
也可以通过配置来开启MySQL的缓存
当缓存开启后,在同样查询环境以及数据下,会直接在缓存中返回结果
缓存虽然能够提升数据库的查询性能,但是也带来了额外的开销
每次查询完后,都要进行一次缓存操作,失效后还要销毁
5 事务
5.1 事务概念
事务就是逻辑上的一组操作,要么都执行,要么都不执行
示例:
A给B转账2000元时,这个转账操作涉及两个关键操作
1,将A的余额扣除2000
2,将B的余额增加2000
事务会把这两个操作看作一个整体,这个整体内的操作要么都成功,要么都失败
5.2 数据库事务
数据库事务可以保证多个对数据库的操作(也就是SQL语句)构成一个逻辑上的整体
构成这个逻辑上的整体的这些数据库操作遵循: 要么全部执行成功,要么全部不执行
# 开启一个事务
START TRANSACTION;
# 多条 SQL 语句
SQL1,SQL2...
## 提交事务
COMMIT;
5.3 事务的ACID特性
1,原子性(Atomicity): 事务是最小的执行单位,不允许分割
事务的原子性确保动作要么全部完成,要么全部失败
2,一致性(Consistency): 执行事务前后,数据保持一致
如转账业务中,无论事务是否成功,收款人和打款人总额不变
3,隔离性(Isolation): 并发访问数据库时,一个用户的事务不会被其它事务干扰
各并发事务之间的数据是独立的
4,持久性(Durabilily): 一个事务被提交后,它对数据库中数据的改变是持久的
即使数据库发生了故障,也不会对其有影响
事务ACID的实现原理:
在MySQL的InnoDB中:
通过redo log重做日志来保证事务的持久性
使用undo log回滚日志保证事务的原子性
使用锁机制,MVCC等手段保证事务的隔离性
当保证了事务的原子性,持久性,隔离性后,一致性才能得到保障
5.4 并发事务带来的问题
在应用程序中,多个事务可能并发运行,经常会操作相同的数据来完成各自的任务(多个用户对同一数据进行操作),并发虽然是必须的,但可能导致以下问题:
1,脏读: 当一个事务A正在访问数据并对数据进行了修改,而这种修改还没有提交到数据库中
这时另一个事务B也访问了这个数据,然后使用了这个数据
那么事务B读到的数据就是"脏数据",依据"脏数据"所做的操作可能是不正确的
2,丢失修改: 指在一个事务A读取一个数据时,另一个事务B也访问了该数据
那么在第一个事务A中修改了该数据后,第二个事务B也修改了该数据
这样第一个事务A内修改的结果就会被丢失
3,不可重读: 指在一个事务A内可能多次读取同一数据,在这个事务没有结束时
另一个事务B也访问了该数据,那么在第一个事务A中的两次读取之间
由于第二个事务B的修改导致第一个事务A两次读取同一个数据,但得到了不同的值
这样发生在一个事务A内两次读取的数据不一样的情况,称为不可重读性
4,幻读: 幻读与不可重读类似,当一个事务A读取了几行数据后
另一个事务B插入了一些数据,在A随后的读取中,发现多了一些"原本不存在的记录"
像幻觉一样,称为幻读
5.5 事务隔离级别
SQL标准定义了4个隔离级别:
READ-UNCOMMITTED 读取未提交
最低的隔离级别,允许读取尚未提交的数据变更
可能会导致脏读,幻读,不可重复读
READ-COMMITTED 读取已提交
允许读取并发事务已经提交的数据
可以阻止脏读,但是幻读和不可重复读仍有可能发生
REPEATABLE-READ 可重复读
对同一记录多次读取结果都是一致的,除非数据被本事务自己修改
可以阻止脏读和不可重复读,但幻读仍有可能发生
SERIALIZABLE 可串行化
最高的隔离级别,完全服从ACID,所有事物依次执行,事物之间无法干扰
5.6 MySQL默认隔离级别
InnoDB默认支持的隔离级别是REPEATABLE-READ(可重复读)
隔离级别越低,事物请求的锁越少
大部分数据库系统的隔离级别都是READ-COMMITTED(读取提交内容)
但InnoDB默认使用的REPEATABLE-READ(可重复读) 不会有性能损失
InnoDB在分布式事物的情况下一般用到 SERIALIZABLE(可串行化) 隔离级别
6 MVCC 多版本并发控制
6.1 MVCC介绍
MVCC在MySQL的InnoDB中的实现主要是为了提高数据库并发性能
用更好的方式去处理读-写冲突,即使有读写冲突,也能做到不加锁,非阻塞并发读
6.1.1 当前读和快照读
当前读:
读取的是记录的最新版本,读取的同时还要保证其它并发事务不能修改当前记录
会对读取的记录进行加锁
快照读:
即不加锁的非阻塞读,基于MVCC
MVCC可以看作行级锁的一个变种,在很多情况下,避免了加锁操作降低了开销
快照读即读取到的并不一定是数据的最新版本,可能是之前的版本
MVCC就是为了实现读-写冲突不加锁,这个读是"快照读"
6.2 MVCC好处
MVCC是一种用来解决读写冲突的无锁并发控制
也就是为事务分配单向增长的时间戳,为每个修改保存一个版本 版本与事务时间戳关联
读操作只读该事务开始前的数据库快照,所以MVCC可以解决:
1,在并发读写记录时,不用加锁,提高了并发性能
2,还可以解决脏读,幻读,不可重复读,但不能解决更新丢失的问题
6.3 MVCC原理
MVCC依赖于记录中的3个隐式字段,undo日志,ReadView来实现的
1,3个隐式字段
DB_TRX_ID: 最近修改该记录的事务ID
DB_ROLL_PTR: 回滚指针,指向这条记录的上一个版本
DB_ROW_ID: 隐藏的自增主键
2,undo日志
undo日志主要分为两种
insert undo log: 代表事务insert新记录时产生的undo log
只在事务回滚时需要 并在事务被提交后可以被丢弃
update undo log: 事务在进行update或delete时产生的undo log
不仅在事务回滚时需要,在快照读时也需要 不能随便删除
3,ReadView 读视图
ReadView就是事务进行快照读操作产生的读视图,在该事务执行的快照读的那一刻
会生成数据库系统当前的一个快照,记录并维护系统当前活跃事务的ID
当某个事务执行快照读时,对该记录创建一个ReadView,把它比作条件用来判断当前事务能看到哪个版本的数据
既可能是当前最新的数据,也可能是该行记录的undo log里某个版本的数据