MySQL是非常灵活的一款数据库,虽然它不是绝对完美,但它的灵活足够适应很多高要求的环境。为了发挥MySQL的性能并很好的使用它,我们就得先了解其设计。MySQL的灵活主要体现在我们可以通过不同的配置使他在不同的硬件上都能运行的很好。但是MySQL最重要,与种不同的特性是它的存储引擎架构,这种架构将查询处理及其他系统任务和数据的存储/提取相分离。

1.MySQL的逻辑架构

mysql逻辑或 mysql逻辑结构设计_死锁

如上图,我们可以简单的将其逻辑架构分为3层

(1)网络接口层:主要负责接受连接,并读写连接对应的内容,这点和我们平时所写的网络服务器的I/O接口层基本相似

(2)请求处理层:如上图所示,该层主要是对请求SQL语句进行解析,解析之后或是进一步对请求的SQL语句进行优化,或是直接在缓存中找到请求的内容

(3)存储引擎层:该层主要负责数据的提取和存储

(1)连接管理

MySQL的每个客户端连接都会在服务器拥有一个线程,该线程的查询只会在这个单独的线程中去执行。服务器会负责缓存该线程,因此不需要为每个新连接创建或销毁线程(线程池)

(2)优化与执行

MySQL会解析查询,并创建内部数据结构(解析树),然后对其进行各种优化,包括重写查询,决定表的读写顺序,以及选择合适的索引等。用户可以通过explain来查看查询优化过程,从而可知服务器是如何进行查询优化决策的。需要注意的是优化器并不需要知道存储引擎是什么,但不同的存储引擎对优化是有影响的

2.并发控制

(1)读写锁

当我们的多个用户同时对数据库中的一张表进行读操作,这并不会产生什么问题。但是如果此时有一个进程在修改表中的某条数据,这就会产生不可预料的事情了。为了防止类似的事情发生,MySQL采用了俩中锁:共享锁和排他锁。这俩中锁从概念上就很好理解,共享意思持有这些锁的线程互相不阻塞,对应此处就是一张表几个线程可以同时读。排他则意味着只要有一个线程获得该锁,则其他的所有线程无论读写都会被阻塞

(2)锁粒度

能够提高并发性的一种方式就是让锁的对象更具有选择性。尽量只锁定真正需要修改的数据,而不是有关的无关的都锁。锁定的资源(临界区)越少,则并发度也就越高,只要相互之间不发生竞争即可。刚才的说法其实只是一种理想,真实环境下,我们创建锁,加锁,解锁,销毁锁也都会也一定的代价,那么你把锁的对象缩小,对应的锁粒度就会增加,锁粒度一旦增加,那么大量的加锁,解锁操作是不是会降低性能。所以我们是不是因该根据实际的应运场景来在这俩者中寻找出最适合该场景的一个平衡点?

MySQL的各种引擎支持如下俩种锁策略

表锁:表锁是MySQL中最基本的策略,并且是开销最小的策略。表锁会锁定整张表,一个用户对表进行写操作(插入,删除,跟新)前,需先获得写锁,这样就会阻塞其他用户对表进行的所有操作。只有没有写锁时,其他用户才能获得该表的读锁,读锁之间是不阻塞的上文有提到的。

行锁:行锁可以最大程度的支持并发处理(也同时带来了最大的锁开销)InnoDB支持的就是行锁,这里所说的锁都是只在存储引擎中的实现,服务器是完全不了解存储引擎的锁实现的。

3.事务

对数据库而言事务就是一组原子的SQL查询(注意这里所所的查询可不单指select哦),或者说是一个独立的单元。如果数据库引擎能够成功的对数据库进行该组内的全部查询语句,那么就执行该组查询。如果有一条不能执行(例如程序崩溃导致),那么所有的语句都不会执行

事物具有ACID特性,分别如下

原子性:一个事务必须被视为一个不可分割的最小单位,整个事务的操作要么全部提交成功,要么失败回滚

一致性:数据库总是从一个一致性的状态转换到另一个一致性的状态

隔离性:通常来说在一个事务所做的修改在最终提交之前,对其他事务是不可见的

持久性:一旦事务提交,则其所做的修改就会永久保存

就像锁粒度的升级会增加系统开销一样,这种事务处理过程中额外的安全性,也同样会使数据库做更多的工作。一个实现ACID的数据库比没有实现的要复杂太多。所以MySQL提供多种引擎,用户可根据需求在不需要事务特性的使用中选择其他引擎

(1)事务的隔离级别

隔离其实是很复杂的,在SQL中定义了4种隔离级别,每一种级别都规定了一个事务所做的修改,哪些事务和事务间是可见的哪些是不可见的。较低级别的隔离可以执行更高的并发,系统的开销也更低

几种隔离级别

未提交读:事务中的修改即使没有提交,对其他事务也都是可见的。事务可以读取为提交的数据,这也被称为脏读。这种级别性能也就那样,但却会导致很多问题

提交读:大多数数据库默认的就是该级别。一个事务开始时只能看到已提交的事务。换句话说,一个事务从开始到提交前,所做的任何修改对其他事物都是不可见的

可重复读:解决了脏读问题,但是却无法解决幻读问题(是指,当某个事务读取某个范围内的记录时,另一个事务又在该范围内插入了新数据,当该事务在此读取该范围内的数据时,会产生幻行)InnoDB通过MVVC解决了幻读问题

可串行化是最高级别的隔离,它通过强制事务串行化执行,避免了前面所说的幻读问题

(2)死锁

当多个事务试图以不同的顺序锁定资源时,就可能会产生死锁。

实例如下

mysql逻辑或 mysql逻辑结构设计_mysql逻辑或_02

如上图中的事务1和事务2所示,如果俩事务都先执行完了第一条UPDATE操作,那么当分别同时在执行第二条时,就会陷入死锁状态即相互等

为了解决上述问题InnoDB通过检测死锁循环依赖,并立即返回一个错误。这种方式很有效,否则死锁会导致查询变的非常慢。InnoDB目前处理死锁的方法是,将持有最少行级锁的事物进行回滚(这是相对比较简单的死锁回滚算法)