最高层客户端,中间是服务器(sql查询及解析器),最底层是存储引擎(MySQL是InnoDB),通过API访问,执行事务。
当客户端连接到MySQL服务器时,服务器需要对其进行认证。认证基于用户名、原始主机信息、密码。连接成功后,会验证该客户端是否具有执行某个查询的权限。
服务器层和存储引擎层的并发控制
通过锁系统来解决,共享锁,排他锁,也成为读锁和写锁。读锁,多个用户同一时刻同时读取同一个资源,互不干扰。写锁,会阻塞其他的写锁和读锁。
一种提高共享资源并发性的方式是让锁定对象更有选择性(细粒度?)。
所谓锁策略,就是在锁的开销和数据的安全性之间寻求平衡(锁的开销过大会影响系统性能)。
表锁是MySQL中最基本的锁策略,并且是开销最小的策略(粒度大,开销就小。相反粒度小,开销大)。table lock,锁定整张表,用户对表INSERT、DELETE、UPDATE时会对表产生写锁,阻塞其他用户对表的读写操作。
行级锁,row lock。最大程度支持并发操作,最大的锁开销。
事务
事务是一组原子性的SQL查询or独立的工作单元。事务内的语句,要么全部执行成功,要么全部执行失败。一句失败,全部失败。
ACID,Atomicity原子性,Consistency一致性,Isolation隔离性,Durability持久性。
- 原子性表示一个事务必须被视为一个不可分割的最小工作单元,整个事务中的所有操作要么全部提交成功,要么全部失败回滚rollback
- 一致性,数据库从一个一致性状态转换到另一个一致性状态。确保数据库的安全性。
- 隔离性,一个事务所作的修改在最终提交前,对其他事务是不可见的。
- 持久性,一旦事务提交,所作的修改会永久保存在数据库。
在MySQL中用户可以选择非事务型的存储引擎,获得更高的性能。
封锁
要保证事务的ACID特性,就要对数据进行封锁。否则会造成丢失修改、不可重复度、读脏数据三种情况。因为数据的不一致性导致事务的隔离性被破坏。
封锁有三级协议:
- 一级封锁协议,事务T在修改数据R之前必须先对其加写锁,直到事务结束才释放。
- 二级封锁协议,在一级封锁协议基础上增加事务T在读取数据之前必须对其加读锁,读完释放读锁。
- 三级封锁协议,在一级封锁协议基础上增加事务T在读取数据之前必须对其加读锁,事务结束后释放读锁。
注意三级是在事务结束释放读锁,二级是读取后释放读锁,明显三级要求更高。一级防止丢失修改,二级防止读脏数据,三级防止不可重复读。
活锁和死锁
活锁,一个事务永久等待的情况。避免活锁的简单方法是采用先来先服务的策略。
死锁是指两个事务在同一个资源上相互占用,并请求对方占用的资源,从而导致恶性循环的现象。
InnoDB目前处理死锁的办法是,将持有最少行级排他锁的事务进行回滚。
并发调度的可串行性
可串行化调度,当多个事务的并发执行是正确的,当且仅当其结果与按一次序串行执行这些事务时的结果相同。可串行性时并发事务正确调度的准则。
事务日志
事务日志可以帮助提高事务的效率。存储引擎在修改表的数据时只需要修改其内存拷贝,再把该修改行为记录到持久再硬盘上的事务日志中。这样的行为称为预写式日志WAL,HDFS中namenode也是预写式日志。
InnoDB采用的是两阶段锁定协议
在事务执行过程中,随时可以执行锁定,锁只有在执行COMMIT或者ROLLBACK才会释放。第一阶段加锁,第二阶段释放锁。
InnoDB存储引擎
InnoDB是MySQL的默认事务型引擎,用来处理大量短期事务,很少被回滚。
采用MVCC来支持高并发(需要专门学一下MVCC),实现四个标准隔离级别。