如何彻底搞懂Mysql事务原理( 二 )

既然redo log也需要在事务提交时将日志写入磁盘 , 为什么它比直接将Buffer Pool中修改的数据写入磁盘(即刷脏)要快呢?主要有以下两方面的原因:

  • 刷脏是随机IO , 因为每次修改的数据位置随机 , 但写redo log是追加操作 , 属于顺序IO 。
  • 刷脏是以数据页(Page)为单位的 , MySQL默认页大小是16KB , 一个Page上一个小修改都要整页写入;而redo log中只包含真正需要写入的部分 , 无效IO大大减少 。
2、undo log
undo log 的写入时机与redo log一致 。
InnoDB实现回滚 , 靠的是undo log:当事务对数据库进行修改时 , InnoDB会生成对应的undo log;如果事务执行失败或调用了rollback , 导致事务需要回滚 , 便可以利用undo log中的信息将数据回滚到修改之前的样子 。
undo log属于逻辑日志 , 它记录的是sql执行相关的信息 。当发生回滚时 , InnoDB会根据undo log的内容做与之前相反的工作:对于每个insert , 回滚时会执行delete;对于每个delete , 回滚时会执行insert;对于每个update , 回滚时会执行一个相反的update , 把数据改回去 。以update操作为例:当事务执行update时 , 其生成的undo log中会包含被修改行的主键(以便知道修改了哪些行)、修改了哪些列、这些列在修改前后的值等信息 , 回滚时便可以使用这些信息将数据还原到update之前的状态 。
三、Mysql的锁机制当数据库有并发事务的时候 , 可能会产生数据的不一致 , 这时候需要一些机制来保证访问的次序 , mysql的锁机制可以达到该目的
1. 按照锁的粒度分数据库锁有哪些?锁机制与InnoDB锁算法
在关系型数据库中 , 可以按照锁的粒度把数据库锁分为行级锁(INNODB引擎)、表级锁(MYISAM引擎)和页级锁(BDB引擎 ) 。
MyISAM和InnoDB存储引擎使用的锁:
  • MyISAM采用表级锁(table-level locking) 。
  • InnoDB支持行级锁(row-level locking)和表级锁 , 默认为行级锁
行级锁:行级锁是Mysql中锁定粒度最细的一种锁 , 表示只针对当前操作的行进行加锁 。行级锁能大大减少数据库操作的冲突 。其加锁粒度最小 , 但加锁的开销也最大 。行级锁分为共享锁 和 排他锁 。
特点:开销大 , 加锁慢;会出现死锁;锁定粒度最小 , 发生锁冲突的概率最低 , 并发度也最高 。
表级锁:表级锁是MySQL中锁定粒度最大的一种锁 , 表示对当前操作的整张表加锁 , 它实现简单 , 资源消耗较少 , 被大部分MySQL引擎支持 。最常使用的MYISAM与INNODB都支持表级锁定 。表级锁定分为表共享读锁(共享锁)与表独占写锁(排他锁) 。
特点:开销小 , 加锁快;不会出现死锁;锁定粒度大 , 发出锁冲突的概率最高 , 并发度最低 。
页级锁 :页级锁是MySQL中锁定粒度介于行级锁和表级锁中间的一种锁 。表级锁速度快 , 但冲突多 , 行级冲突少 , 但速度慢 。所以取了折衷的页级 , 一次锁定相邻的一组记录 。
特点:开销和加锁时间界于表锁和行锁之间;会出现死锁;锁定粒度界于表锁和行锁之间 , 并发度一般
从锁的类别上来讲 , 有共享锁和排他锁 。
  • 共享锁(S锁): 又叫做读锁 。当用户要进行数据的读取时 , 对数据加上共享锁 。共享锁可以同时加上多个 。事务T对数据对象A加上共享锁 , 则事务T可以读A但不能修改A , 其他事务只能再对A加共享锁 , 而不能加排他锁 , 直到T释放A上的共享锁 。这保证了其他事务可以读A , 但在T释放A上的共享锁之前不能对A做任何修改 。
  • 排他锁(X锁): 又叫做写锁 。当用户要进行数据的写入时 , 对数据加上排他锁 。排他锁只可以加一个 。若事务T对数据对象A加上排他锁 , 事务T可以读A也可以修改A , 其他事务不能再对A加任何锁 , 直到T释放A上的锁 。这保证了其他事务在T释放A上的排他锁之前不能再读取和修改A 。
2、InnoDB锁的特性
由于 MySQL 的Innodb引擎的行锁是针对索引加的锁,不是针对记录加的锁,所以虽然是访问不同行的记录,但是如果是使用相同的索引键,是会出现锁冲突的 。


推荐阅读