第一层的服务不是MySQL独有的,大多数是基于网络的客户端/服务端的工具,如链接处理、受权认证、安全等等。数据库
第二层就是MySQL的核心功能,包括查询解析、分析、优化、缓存以及全部的内置函数,全部的跨存储引擎的功能都在这一层实现:存储过程、触发器、视图等。缓存
第三层包含了存储引擎,主要负责MySQL中数据的存储和提取。安全
每一个客户端链接都会服务器进程中拥有一个线程,这个链接的查询只会在这个单独的线程中执行,该线程只能轮流在某个CPU核心或者CPU中运行,服务器会缓存线程,因此不须要对每一个链接新建或者销毁一个线程(能够复用缓存中的线程)。服务器
当客户端链接到MySQL时服务器须要对其进行认证,若是认证成功,服务器会继续验证该客户是否有执行某个待定查询的权限。网络
MySQL会解析查询,而且建立内部数据结构(解析树),而后对其进行各类优化,包括重写查询SQL、决定表的读取顺序,以及选择合适的索引等。数据结构
对于一个SELECT查询语句来讲:在解析查询以前,服务器会先检查查询缓存,若是可以在其中找到对应的查询,服务器会直接返回结果,不须要再执行查询解析、优化和执行整个过程。架构
好比有一张表,多个线程对这张表进行操做,加入恰好有一个线程在对一条数据更改,另外一个线程也对其进行读取操做,那么进行读操做的这个线程可能读到的数据是不正确的,怎么解决这个问题呢?这时就用到了并发控制,主要是经过两种锁来控制的:读锁(共享锁)、写锁(排他锁)
并发
读锁是共享的,或者说是相互不阻塞的,即对个线程读取同一个资源,互不干扰;写锁是排他的,也就是说只要有一个线程对其进行写操做,那么其余的读和写线程将都会被阻塞。只有这样才能保证才能保证在给定的时间内只有一个线程在写操做,并防止其余线程读取正在写入的数据。函数
最理想的状况是:须要写入哪一个对象就锁定哪一个对象。尽可能只锁定须要修改的部分数据,而不是全部的数据。在任什么时候候,在给定的资源上,锁定的数据越少,系统的并发程度越高。工具
可是还有一个问题,加锁也会消耗资源,锁的各类操做:得到锁、检查锁是否已经解除、释放锁等,都会增长系统的开销,若是花费大量的时间来管理锁,而不是存取数据,那么系统的性能将会受到影响。
所谓的锁策略,就是在锁的开销和数据的彻底性之间寻求平衡。
表锁是MySQL中最基本的锁策略,而且是开销最小的策略(意味着并发程度低),可是表锁的缺点是在执行插入、删除、更改的操做时会使其余的用户线程阻塞。(注意:读锁之间是互不影响的)。另外写锁比读锁的优先级更高。写锁能够插到读锁中,可是读锁却不能插到写锁中。
行级锁:能够最大程度的支持并发处理(可是同时也带来了更大的锁开销)最典型的就是InnoDB存储引擎,行级锁只在存储引擎层实现。
最重要的事务终于到啦,事务即ACID(原子性、一致性、隔离性、持久性),在开始讲这四个特性以前咱们先举一个最经典的例子:某帐户存了1000元,如今用户A要往里面存200元、用户B要往出来取200元。
原子性:一个事务必须被视为不可分割的最小工做单元,整个事务的全部操做要么所有提交完成,要么所有失败回滚,对于一个事务来讲不可能执行其中的一部分。那上面例子来讲:A要从帐户取200须要执行如下四步操做:
1 START TRANSACTION; 2 SELECT '金额' FROM '帐户表' WHERE user_id = 1221221; 3 UPDATE '帐户表' SET '金额' = '金额' - 200 WHERE user_id = 1221221; 4 COMMIT;
解释:1.开启事务 ,2.查询帐户有没有200元 ,3.扣除金额 , 4.提交事务。
原子性就是指这四步完整执行不可再分。
一致性:数据库从一个一致性的状态转换为另外一个一致性的状态。就上面那个例子:若是在第三步执行完系统崩溃,帐户中的金额仍是1000元,由于一个事务没有执行完,在最终提交前是不会保存到数据库中的。
隔离性:一般来说一个事务在最终提交前,对其余事务是不可见的。就以前例子来讲,第三步执行完,在没提交以前B帐户来看到的金额仍然是1000元。是不可见的。
持久性:事务一旦提交其所作的修改就会永远的被保存到数据库中,即便系统崩溃也不会丢失。
一个实现了事务的数据库相比于没有实现事务的数据库它须要更强的CPU处理能力、更大的内存、更多的磁盘空间。对于有些不须要事务的查询类应用选择一个非事务型的存储引擎能够得到更高的性能。
一共有四种隔离级别先简单作个介绍:
A.READ UNCOMMIT(读未提交)
在这个隔离级别中,事务的修改,即便没有提交,对其余的事务也是可见的。事务能够读到未提交的数据,这些数据也被称为脏读。
B.READ COMMIT(读已提交)(不可重复读)
大多数数据库系统的默认隔离级别都是读已提交,可是MySQL不是,MySQL的默认隔离级别是可重复读。简单说就是一个事务开始时只能 “看见” 已经提交的事务所作的修改,换句话说,一个事务从开始到提交这个过程当中所作的全部修改对其余事务是不可见的。这个级别对于两次执行相同状况的查询,可能会获得不一样的结果。
C.REPEATABLE READ(可重复读)
该级别保证了在同一个事务中屡次读取一样的记录结果是一致的,可是它没法解决幻读的问题。
D.SERIALIZABLE(可串行化)
是最高的隔离级别。它经过强制事务串行化执行,避免了全部问题,他会在读取的每一行记录上面都加锁,因此可能致使大量的超时与锁等待的问题,并发低。
讲几个概念:
1.脏读:A用户把钱取出没有提交,B用户读取到修改了的金额为800,过一会A由于异常事务回滚,B再次读取发现值变为1000,两次不同,第一次读到的是脏数据。
2.不能够重复读:B读到数据为1000后,A修改数据为800而且提交,B再次读取为800,两次数据不一致。
3.幻读:与不可重复读相似:B读到一个表里有10条记录,A插了一条并提交,B再次读为11条,感受发生幻觉同样。
不一样隔离级别引起的问题:
多个事务在同一资源上相互占有,而且请求锁定对方占用的资源,从而致使恶性循环的现象。
数据库系统实现了各类死锁检测和死锁超时机制。InnoDB目前处理死锁的方法是:将持有最少行排它锁的事务进行回滚。
事务日志能够提升事务的效率,使用事务日志时:存储引擎在修改表数据时只须要修改其内存拷贝,再把该修改行为记录到持久在硬盘上的事务日志中,不用每次将修改的数据自己持久到硬盘。事务日志采用追加的方式,写日志的操做是磁盘上的一小块区域内的顺序I/O.事务日志持久后,内存中被修改的数据将在后台慢慢刷回到磁盘。因此一共须要两次磁盘I/O:一次写日志磁盘I/O,一次刷回磁盘I/O.
1.自动提交:MySQL默认采用自动提交的方式。好比每一个查询就是一个事务执行完自动提交。
2.非事务型存储引擎如:MyISAM无回滚功能。
能够认为MVCC是行级锁的一个变种,它在不少状况下避免了加锁,MVCC的实现是经过保存数据在某个时间的快照来实现的。
InnoDB的MVCC,是经过在每行记录后面保存两个隐藏的列来实现的,这两个列一个保存了行的建立时间,一个保存了行的删除时间,存储的不是真正时间而是系统的版本号。每一个新事物开始系统版本号自动递增。事物开始时刻的版本号做为事物的版本号,用来和查询到的每行记录版本号进行比较。
MVCC只在可重复读和读已提交两个隔离级别下工做,其余两个级别都和MVCC不兼容。由于读未提交老是读取最新的数据行,不符合当前事物版本的数据行。可串行化会对全部行加锁。
个人理解其实MVCC就跟CAS是一个原理,就是一个比较并交换的过程。