|
最近我觉得自己各项技能都是随着工作而学习的,感觉总有一些知识没有掌握,特准备在基于《Mysql权威指南》和《高性能Mysql》这两本书来系统学习下,把每次学习的笔记整理成博客的形式。一是为了加深自己的印象,二是为了给自己提供更好的学习能力,三是和大家共同分享。 1、逻辑架构 第一层:并不是Mysql独有,大多数基于网络客户端、服务器工具,例如:连接处理、授权认证、安全等 第二层:核心服务层,包括查询解析、分析、优化、缓存、内置函数,所有跨域存储引擎都在这一层:存储过程、触发器、视图 第三层:包含存储引擎,负责Mysql数据的存储和提取。 2、Mysql的并发控制 Mysql在服务器层和存储引擎层的的并发控制。 2.1 读写锁 在处理并发读写时可以通过实现一个由两种类型的锁组成的锁系统来解决问题,这两种类型的锁被称为共享锁和排他锁(exclusive lock),也叫读锁和写锁 描述下锁的概念:读锁是共享的,写锁是排他的。 在实际数据库应用中每时每刻都在发生锁定,Mysql锁内部管理透明。 2.3 锁粒度 一种提高共享资源并发性的方式就是让锁定对象更有选择性。尽量只锁定需要修改的部分数据。更理想的方式只对修改的数据片进行精确锁定。锁定的数据量越少并发程度越高。 加锁也是消耗资源的,锁的各种操作,包括获得锁、检测锁是否是否已解除、释放锁等。 所谓的锁策略就是锁的开销和数据的安全性之间寻求平衡,这种平衡当然也会影响性能。 Mysql提供了多种选择,每种存储引擎都可以实现自己的锁策略和锁粒度。下面来介绍两种锁策略: 1、表锁 Mysql基本策略,开销最小。 2、行级锁 最大程度的支持并发,同时也带来了最大的锁开销。行级锁只在存储引擎层实现,而Mysql服务器层没有实现。服务器层完全不了解存储引擎中的锁实现。 所有的存储引擎都以自己的方式显现了锁机制。 3、事务 ACID原则 原子性atomicity、一致性consistency、隔离性isolation、持久性durability 1、隔离级别 read uncommitted(未提交读),事务可以读取到未提交的数据,称为脏读 read committed,一个事务未提交之前所做的对其他事务都是不可见的 repeatable read,解决了脏读问题,该级别保证了同一个事务中多次读取同样记录的结果是一致的。但是理论上无法解决幻读,所谓幻读是,当某个事务正在读取某一个范围的记录时,另外一个事务又向该范围插入一条新的记录,当之前事务再次读取时会产生幻行。Mysql的InnoDB和XtrsDB存储引擎通过多版本并发控制(MVVC,multiversion concurrency control )解决了幻读问题。 serializable可串行化,串行执行,隔离级别最高,超时和锁争用严重,不常用 2、死锁 死锁是指两个或多个事务在同一资源上相互占用,并请求锁定对方占用的资源,从而导致恶性循环。当事务试图以不同的顺序锁定资源时,就可能产生死锁。多个事务同时锁定同一个资源时也会产生死锁。 例如: 事务1: start transaction; update goods set price = 20 where goods_id = 4 and date=’2015-4-22’; update goods set price = 30 where goods_id = 3 and date = ‘2015-4-22’; commit; 事务2: start transction; update goods set price = 40 where goods_id = 3 and date = ‘2015-4-22’; update goods set price = 50 where goods_id = 4 and date = ‘2015-4-22’; commit; 为了解决这种问题,数据库系统实现了各种死锁检测和死锁超时的机制,越复杂的系统,比如:InnoDB存储引擎,越能检测到死锁的循环依赖,并立即返回一个错误。 还有一种解放方式,当查询的时间达到锁等待超时的设定后放弃锁请求。InnoDB目前处理死锁的方法是:将持有最少行级锁排他锁事务进行回滚。 锁的行为和顺序和存储引擎相关。以同样的顺序执行语句,有些存储引擎会产生死锁有些不会。死锁有双重原因:真正的数据冲突;存储引擎的实现方式。 3、事务日志 提高事务效率,如果修改的已经记录到事务日志并持久化,但数据本身还没回写磁盘,此时系统崩溃,存储引擎在重启时能够自动恢复这部分修改的数据。具体实现方式视存储引擎而定。 4、Mysql中的事务 自动提交(autocommit) Mysql默认采用自动提交模式,可以通过设置autocommit变量来启用或禁用自动提交模式: show VARIABLES like ‘autocommit’; 1或on表示启用,0或off表示关闭。 Mysql可以通过执行 set transaction isolation level命令来设置隔离级别,新的隔离级别会在下一个事务开始的时候生效。 例如:set session transaction isolation level read committed; 在事务中混合使用存储引擎 如果在事务中混合使用了事务型和非事务型的表(InnoDB和Myisam)正常提交是不会有问题的,如果事务回滚,非事务型的表变更是无法撤销的,这会导致数据库处于不一致状态。 隐式和显式锁定 InnoDB在事务执行过程中,随时都可以执行锁定,锁只有在执行commit或者rollback的时候才会释放,并且所有的锁都是在同一时刻被释放,前面描述的都是隐式锁,InnoDB会根据隔离级别在需要的时候自动加锁。 另外,InnoDB也支持通过特定的语句进行显示锁定 select … lock in share mode ? 共享锁 select … for update ? 排他锁 Mysql也支持lock tables和unlock tables,这都是在服务器层实现的,和存储引擎无关。 5、多版本并发控制 Mysql的大多数事务型存储引擎实现都不是简单的行级锁。基于提升并发性考虑,一般都同时实现了多版本并发控制(MVCC),包括Oracle、PostgreSQL。不过实现各不相同。 可以认为MVCC是行级锁一个变种,但是他很多情况下避免了加锁操作,开销更低。虽然实现机制有所不同,但大都实现了非阻塞的读操作,写操作也只锁定必要的行。 MVCC的实现是通过保存数据在某一个时间点快照来实现的。也就是说不管实现时间多长,每个事物看到的数据都是一致的。 分为乐观(optimistic)并发控制和悲观(pressimistic)并发控制。下面来说说是如何工作的: InnoDB的MVCC是通过在每行记录后面保存两个隐藏的列来实现。这两个列一个保存了行的创建时间,一个保存行的过期时间(删除时间)。当然存储的并不是真实的时间而是系统版本号,每开始一个新的事务,系统版本号都会自动新增。事务开始时刻的系统版本号会作为事务的版本号,用来查询到每行记录的版本号进行比较,下面看下REPEATABLE READ隔离级别下MVCC如何工作: SELECT InnoDB会根据以下条件检查每一行记录: a.InnoDB只查找版本早于当前事务版本的数据行,这样可以确保事务读取的行要么是在开始事务之前已经存在要么是事务自身插入或者修改过的 b.行的删除版本号要么未定义,要么大于当前事务版本号,这样可以确保 |