1.1 MySQL的逻辑架构

MySQL采用分层的架构,服务和数据进行单独分离。主要分为客户端、服务器、存储引擎、磁盘存储四大方面。
1.MySQL架构与历史 - 图1
上层的是为C/S的服务架构,主要包含用户认证,连接处理,安全管理。
中间层为Serve层,包含的是跨存储引擎的功能都是在该层实现,例如 视图、定时任务、存储过程,函数,优化器,解析器,执行计划生成等。
下层为引擎层,MySQL支持插拔式的存储引擎,用户根据实际情况进行选择。该层负责MySQL中数据的存储和提取。服务器通过API和存储引擎打交道。

1.2 并发控制

生活场景中,只要有多个查询在同一时间点对同时修改同一条数据,就会存在并发问题。MySQL的并发控制:服务器层和存储引擎层。

1.2.1 读写锁

读锁也被称之为共享锁,写锁被称为排它锁。读锁直接可以并发执行,排他锁互斥,只有这样才可以保护数据。排他锁拥有比共享锁更高的优先级。

1.2.2 锁粒度

如何提供共享资源的并发性,那就是让锁定的对象更小的粒度,尽量只锁定自己需要修改的资源。然后加锁也是需要消耗资源的,锁的各种操作,加锁,解锁,检测锁等。所以应该评估系统并发性和锁资源消耗找到中间平衡点。
锁的粒度有:库锁、表锁、行锁,而目前行锁是一种比较好的方案。
行锁可以最大程度的支持并发,行级别锁只能在存储引擎级别实现,而innodb支持行锁。

1.3 事务

事务就是一组独立的完整的单元,最好理解的例子就是银行转账。假如小王给小程转账200元,那么存在以下的几个步骤
第一步 查询小王的余额是否超过200元
第二步 从小王的余额里面减去200元
第三步 从小程的余额里面增加200元
以上三个事情必须放到一个事务里面,要么一起执行,要么都不执行(A)。我们通过反证法来理解事务的特性。

  1. 如果转账在第二步时异常断电,那么小王的钱少了200元,但是小程的余额没多200元,这样导致总钱没有平衡,满足不了一致性(C)
  2. 如果在转账的第二步前,小王的钱被全部取出了,但是此时小王又给小程转账了200元,满足不了隔离性(I)
  3. 只要事务提交了,不管发生了什么情况,数据库都会持久保存,这里体现了持久性(D)

故事务拥有A(Atomicity),C(Consistency),I(Isolation),D(Durability)的四个基本特性

1.3.1 隔离级别

分析事务的隔离级别,主要分成四种隔离级别

隔离基本 脏读可能性 不可重复读可能性 幻读可能性 加锁读
READ UNCOMMITTED
READ COMMITTED
REPEATABLE READ
SERIALIZABLE

1.3.2 死锁

死锁是指两个或者多个事务在同一时刻同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环的现象。

事务1:

  1. begin
  2. update ta set name='wang',age=100 where id=1;
  3. update tb set name='zhang',age=200 where id=101;
  4. commit;

事务2:

  1. begin
  2. update tb set name='wang',age=100 where id=101;
  3. update ta set name='zhang',age=200 where id=1;
  4. commit;

如果两个事务都执行完了第一个事务,更新了第一行数据,同时又锁定了该行数据,接着都去执行第二条update语句,却发现该行正好被对方锁定了,双方正好持有对方的锁,造成死锁。数据库为了解决这样的问题,实现了死锁检测和死锁超时机制。目前innodb将持有最少行级排它锁的事务进行回滚。原来回滚的事务只能依赖应用系统重新提交事务。

1.3.3 事务日志

使用事务日志可以提高事务的效率。在使用事务日志系统里面,存储引擎在修改表的数据只需要修改内存里面的数据,然后把修改行为持久化到磁盘的事务日志就可,无需每次将数据持久化到磁盘。这里很重要的一点就是 事务采用的是追加的模式,顺序读写,效率很高。等待事务日志持久化之后,内存里面的数据在慢慢的依赖操作系统的定时刷新机制刷回磁盘。我们称之为预写日志(WAL)。如果发生断电等情况,可以通过WAL有效回复丢失的数据。

1.3.4 MySQL中的事务

查看事务的提交方式

show variables like ‘%autocommit%’;

set autocommit=1;

设置隔离级别

show variables like ‘%isolation%’;

set session transaction isolation level read committed;

innodb采用的是两阶段锁定协议,在事务执行过程中,随时都可以执行锁定,锁只有在commit或者rollback的时候才释放,并且所有的锁都是在同一时间释放,innodb会根据隔离级别在需要的时候自动加锁。

MySQL也支持LOCK TABLES和UNLOCK TABLES,但是这个是服务器层实现的,很存储引擎无关。友情建议:数据库默认使用innodb存储引擎,并且任何时候不要显式的执行LOCK TABLES。

1.4 MVCC

MVCC是行锁的一个变种,主要了为了避免加锁操作,实现了非阻塞读操作,写操作也只锁定必要的行。实现的原理,是通过保存数据在某个时间点的快照来实现的。同一个事务在事务开始和结束看到的数据肯定是一样的;但是不同时候,每个事务对同一张表看到的数据又是不一样的。

实现的原理是通过每行记录后面保存了两个掩藏的列来实现,一个是用来保存行创建时间,另外一个用来保存行的删除时间。下面讨论在RR级别下,MVCC的具体实现过程

SELECT:
INNODB会根据两个条件来判断每行记录:
第一 innodb只查找早于当前事务版本的数据行,保存事务是在本次事务之前就已经提交的。
第二 行的删除版本要么未定义,要么大于当前事务版本,这样保存数据在事务开始之前没有被删除。

INSERT:
Innodb为新插入的每一行保存当前系统版本作为行版本号

DELETE:
Innodb为新删除的每一行保存当前系统版本作为行删除标识

UPDATE:
Innodb为新插入的行保留当前系统版本作为行版本号,并且保存当前系统版本号作为行删除标识

1.5 MySQL的存储引擎

修改表存储引擎
alter table ta engine=innodb;
下面为各个存储引擎对比图
1.MySQL架构与历史 - 图2