1.1 MySQL逻辑架构 *
No.1 客户端、连接/线程处理
连接处理
授权认证
安全
No.2 解析器、查询缓存
查询解析、分析、优化、缓存
内置函数
跨存储引擎:存储过程、触发器、视图等
No.3 存储引擎
通过api与服务器通信
响应上层服务器请求
数据的存储和提取
MySQL存储引擎(Storage Engine),是指数据的存储/读取相关的逻辑模块。而存储引擎API(table handler)是指Storage Engine与MySQL优化器间的接口。比如,新增一个存储引擎,如何实现MySQL服务层对存储存储引擎访问呢?MySQL服务访问的存储引擎是接口就是抽象存储引擎API,新存储引擎只需要实现相应的抽象存储引擎API接口,就可以实现MySQL Service对存储引擎的访问。
MySQL插件式存储引擎架构,促使MySQL以更加开放的姿态,接受更多的存储引擎。抽象存储引擎接口是在v3.22提升到v3.23时引入的设计。在快速集成InnoDB存储引擎阶段中起了很大的作用。
抽象存储引擎API接口是通过抽象类handler来实现,handler类提供诸如打开/关闭table、扫表、查询Key数据、写记录、删除记录等基础操作方法。每一个存储引擎通过继承handler类,实现以上提到的方法,在方法里面实现对底层存储引擎的读写接口的转调。从5.0版本开始,为了避免在初始化、事务提交、保存事务点、回滚操作时需要操作one-table实例,引入了handlerton结构让存储引擎提供了发生上面提到操作时的钩子操作。
作者:itopcat来源:CSDN原文:https://blog.csdn.net/itopcat/article/details/73614101
1.2 并发控制
只要有多个查询需要在同一时刻修改数据,都会产生并发问题,我们一般用锁来解决。
1.2.1 读写锁
共享锁:读锁(read lock)互相不阻塞
排他锁:写锁(write lock)
写锁 > 读锁
1.2.2 锁粒度
表锁(table lock)
服务层 > 存储引擎
行级锁(row lock)
存储引擎实现、服务层没有必要
最大程度地支持并发处理(同时也带来了锁开销)
1.3 事务
事务的特性(ACID):
原子性(atomicity)事务中所有操作要么全部成功,要不全部失败回滚
一致性(consistency)一致性的状态转换到另一个一致性的状态,不会因为其中一条语句崩溃而影响其他。
隔离性(isolation)通常来说,一个事务在最终提交之前,对其他事务是不可见的
持久性(durability)一旦事务提交,则其所做的修改就会永久保存到数据库中。即使系统崩溃,修改的数据也不会丢失。
隔离级别:
read uncommitted : 读取尚未提交的数据 :哪个问题都不能解决2)
read committed:读取已经提交的数据 :可以解决脏读 ---- oracle默认的3)
repeatable read:重读读取:可以解决脏读 和 不可重复读 ---mysql默认的4)
serializable:串行化:可以解决 脏读 不可重复读 和 虚读---相当于锁表
查看MySQL隔离级别:
SELECT @@tx_isolation
设置MySQL隔离级别
用户可以用SET TRANSACTION语句改变单个会话或者所有新进连接的隔离级别。它的语法如下:
SET [SESSION | GLOBAL] TRANSACTION ISOLATION LEVEL {READ UNCOMMITTED | READ COMMITTED | REPEATABLE READ | SERIALIZABLE}
1、脏读:事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据
2、不可重复读:事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。
3、幻读:系统管理员A将数据库中所有学生的成绩从具体分数改为ABCDE等级,但是系统管理员B就在这个时候插入了一条具体分数的记录,当系统管理员A改结束后发现还有一条记录没有改过来,就好像发生了幻觉一样,这就叫幻读。
小结:不可重复读的和幻读很容易混淆,不可重复读侧重于修改,幻读侧重于新增或删除。解决不可重复读的问题只需锁住满足条件的行,解决幻读需要锁表
要查看详情及例子可参考
https://www.cnblogs.com/huanongying/p/7021555.html
1.3.2 死锁
死锁是指两个或者多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象:
多个事务以不同顺序锁定资源
多个事务同时锁定一个资源
避免死锁的几种方式:
设置加锁顺序:缺点需要事先知道哪些资源用到锁,并知道他们之间获取锁的顺序。
设置加锁时限:缺点是枷锁时限的阀值很难去判定
死锁检测:缺点是还是会出现和设置加锁时限相同的问题
设置线程优先级、也可以尝试随机设置优先级
解决死锁,常采用的方法有:
剥夺资源:从其它进程剥夺足够数量的资源给死锁进程,以解除死锁状态;
撤消进程:可以回滚死锁进程或撤消代价最小的进程。
一条简单SQL的加锁实现分析:
但我自己的实验 “ RR下的无索引 ” 中并没有出现作者提的MySQL作出优化,而是不提交的情况下一直在等待前者提交。
参考:http://hedengcheng.com/?p=771 作者:何登成
1.3.3 事务日志
事务日志可以帮助提高事务的效率。使用事务日志在修改表的数据时只需要修改其内容拷贝,再把该修改记录到持久硬盘上的事务日志中,而不用每次都将修改的数据本身持久到磁盘。
事务日志采用的是追加的方式,因此写日志的操作是磁盘顺序I/O,而不像随机I/O需要在磁盘的多个地方移动磁头,所以采用事务日志的方式相对来说要快得多。
事务日志持久以后,内存中被修改的数据在后台可以慢慢地刷回到磁盘。
1.3.4 MySQL 中的事务
1、MySQL提供了两种事务型的存储引擎:Innodb 和NDB Cluster;另外还有一些第三方存储引擎也支持事务。
2、MySQL默认采用 自动提交 ,如果不是显式地开始一个事务,则每个查询都被当作一个事务执行提交操作:
show variables like 'AUTOCOMMIT’; 查看当前自动提交状态
set AUTOCOMMIT = 0;(0为关闭状态,1为开启状态)临时设置(仅对当前客户端可用)
3、MySQL 服务器层不管理事务,事务是由下层的存储引擎实现的。所以在事务中混合使用存储引擎是不可靠的。
4.隐式和显式锁定。在执行事务过程中,执行锁定都是隐式锁定。一些特定的语句:
SELECT...LOCK IN SHARE MODE
SELECT...FOR UPDATE
LOCK TABLES 等都是显示锁定。
通常不建议使用这些语句,特别不建议使用LOCK TABLES,因为它和事务之间相互影响的话,情况会变得非常复杂。
1.4 多版本并发控制
MySQL 的大多数事务型存储引擎实现的都不是简单的行级锁。基于提升并发性能的考虑,它们一般都同时实现了多版本并发控制(MVCC)。
可以认为MVCC是行级锁的一个变种,它在很多情况下避免了加锁操作,因此开销更低。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的。开始的时间不同,每个事务对同一资源看到的情况是可能不同的。
不同存储引擎的MVCC的实现是不同的,典型的有 乐观并发控制 和 悲观并发控制。
InoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。一个保存了行的创建时间,一个保存行的过期时间。当然存储的并不是实际的时间,而是系统版本号。每开始一个新的事务,系统版本号就会递增,作为事务的版本号,用来和查询到的每行记录的版本号进行比较。
以下看看MVCC具体是如何操作的:
SELECT:
a. InnoDB 只查找早于或者等于当前事务版本的数据行,这样可以确保事务读取的行,要么是在事务开始前存在的,要么是事务自身插入或者修改过的。
b.行的删除版本要么未定义,要么大于当前事务版本号,确保事务读取到的行,在事务开始之前未被删除。
INSERT:
InnoDB 为新插入的每一行保存当前系统版本号作为行版本号。
DELETE
InnoDB 为删除的每一行保存当前系统版本号作为行删除标识。
UPDATE
InnoDB 为插入一行新记录,保存当前系统版本号作为行版本号,同时保存当前系统版本号到原来的行作为行删除标识。
保存这两个额外的系统版本号,使大多数读操作都可以不加锁、操作简单、性能号;不足之处就是需要额外的存储空间,以及一些额外的维护工作。