mysql逻辑架构图:
第一层 客户端
第二层(服务层):针对所有类型的存储引擎可以公共提取的部分。将存储引擎抽离之后的其他部分都在这里。如:查询解析,分析优化,内置函数,存储过程,触发器,视图。
第三层(存储引擎层):存储引擎负责mysql数据的存储和提取。服务器通过API与存储引擎进行通信。这些API屏蔽了不同存储引擎的具体实现差异。存储引擎API包含"开始一个事务","根据主键获取一行数据"等操作。存储引擎本身不会去解析sql。
注:mongdb也有存储引擎。
数据库通过读锁和写锁,又叫共享锁和排它锁,来控制并发事务。
关于锁粒度,mysql交给存储引擎自己去管理,每种存储引擎可以实现自己的锁粒度和锁策略。
不同的锁策略,会带来不同的效果,表锁开销最小,但是并发最差。行级锁并发性能最好,但是开销最大。
尽管锁策略在存储引擎上管理,但是在执行alter table这种操作的时候,服务层会直接使用表所,而忽视存储引擎层的锁机制。
隔离级别:
mysql支持四中隔离级别:
- read uncommitted:未提交读
- read commited 提交读(Oracle的默认隔离级别)
- repeatable read 可重复读(mysql的默认隔离级别)
- serializable 串行化
注:可重复读解决了不可重复读的问题(同一个数据在两次读取的时候结果不一样)。串行化解决了幻读的问题(两次执行同一个where语句结果什么结果条数不一致)。
疑惑:关于序列化,书上说mysql对每一行读的数据都加锁。如果这样做的话,肯定能保证可重复读,但是怎么保证幻读呢,因为对读取的数据进行加锁是不能阻塞insert操作的呢。
死锁:关于死锁的原因,一种是业务场景的操作导致,另外一些,是存储引擎的实现方式导致的。
innodb能够识别到死锁现象,并回滚持有最少排它锁的事务。
事务日志:
事务日志可以提高事务的效率,mysql在update表的时候只需要修改内存中的数据,然后将修改行为记录在硬盘的事务日志中,这个事务的过程就算完了。不需要等待硬盘中的数据文件被update才返回。事务日志是硬盘上的一段顺序存储空间,可不是随机的磁盘存储,每次add都是采取追加的方式,事务日志中的内容会持久化到硬盘数据文件中。这种方式叫做预写式日志,需要写两次硬盘。
如果出现断电,在重启后,可以通过事务日志恢复数据。
注:Mongodb最新的WiredTiger存储引擎也有类似事务日志的概念,不过不叫事务日志,叫做预写日志(WAL: Write-Ahead Logging),因为mongdb没有事务么。