/ Afred's Blog / MySQL技术内幕Innodb存储引擎读书笔记

MySQL技术内幕Innodb存储引擎读书笔记

2014-08-23 posted in [mysql]

MySQL体系结构

在MySQL中,存储引擎是基于数据表的,而不是基于数据库的。

Innodb 存储引擎

Innodb支持事务,具有行锁设计、支持外键的特定,并支持类似于Oracle的非锁定读,即默认情况下,读取操作不会产生锁。Innodb通过使用多版本并发控制(MVCC)获得高并发,并且实现了SQL标准的4种隔离级别,默认为REPEATABLE级别。

MyISAM存储引擎

不支持事务,表锁,全文索引,是MySQL的默认存储引擎。当使用MyISAM存储引擎时,MySQL数据库只缓存索引文件,数据文件的缓存交由操作系统管理。

Innodb存储引擎的锁

Innodb实现了两种标准的行级锁:

共享锁和排他锁的兼容性如下表:

          |       X        |     S        |  
          |----------------|--------------| 
          |       冲突      |    冲突      | 
          |       冲突      |    兼容      | 

如果一个事务已经获得数据表行r的共享锁,那么另外的事务可以立即获得行r的共享锁,称为锁兼容;如果事务想获得行r的排他锁,它必须等待事务释放行r上的共享锁,称为锁不兼容。

一致性的非锁定读操作

Consistent nonlocking read, 是指InnoDB存储引擎通过行多版本控制的方式,来读取当前执行时间数据库中行的数据。如果读取的行正在执行UPDATE、DELETE操作,这时读取操作不会等待行上锁的释放,而是会读取行上的一个快照数据。之所以称为非锁定读,是不需要等待访问的行上X锁释放。快照数据是指该行之前版本的数据。

非锁定读是InnoDB存储引擎默认设定下默认的读取方式。不同事务隔离级别并不都是一致性读,并且快照数据的定义也不同,比如数据表的一行,可能有多个历史版本,多个快照数据。

  1. 查询MySQL事务隔离级别
  
select @@tx_isolation;  

 
select @@global.tx_isolation;   

  
set session transaction isolatin level repeatable read;  

  
set global transaction isolation level repeatable read;  

对读取操作加锁

默认情况下,InnoDB的select操作会使用一致性非锁定读,但是在某些特定情况下,需要对读取操作加锁。InnoDB对select有两种加锁操作:

  1. select … for update
    对读取的行,加X锁,其他事务想要在这些行上加任何锁都会被阻塞。

  2. select … lock in share mode
    对读取的行,加S锁,其他事务可以继续加S锁,但如果尝试加X锁,将会被阻塞。

事务提交或者回滚之后,for update 和 lock in share mode设置的锁才会被释放。

InnoDB行锁算法

Record Lock

单个行记录上的锁,

Gap Lock

间隙锁,锁定一个范围,但不包含记录本身。

Next-Key Lock

Gap Lock + Record Lock,锁定一个范围,并且锁定记录本身。

锁问题

丢失更新

脏读

需要区分脏页和脏数据,脏页是指在缓冲区已经被修改的页,还没有刷新到磁盘,即数据库实例内存中的页和磁盘的页中数据不一致,当然,在刷新到磁盘之前,日志都已经被写入到重做日志文件中。而所谓的脏数据,是指在缓冲区中修改的数据,还没有被提交。对于脏页的读取,是正常操作,并不影响数据的一致性,而脏数据,是没有提交的数据,如果一个事务可以读到另外一个数据未提交的数据,就违反了数据库的隔离性。

不可重复读

一个事务可能会多次读取同一个记录,在该事务没有结束时,如果另外一个事务也访问并修改该记录,会导致第一个事务两次读取的数据不一致。,称为不可重复读。脏读和不可重复读的区别是,脏读读取到了未提交的数据,不可重复读读到的确实是已经提交的数据,但是却违反了数据库的一致性。

InnoDB默认事务隔离级别是 READ REPEATABLE, 采用Next-Key Lock算法,避免了不可重复读的现象。

待续…

comments powered by Disqus