日期:2014-05-16  浏览次数:20449 次

MySQL技术内幕:InnoDB存储引擎读书笔记(下)

?

第六章、锁

  锁是区别文件系统和数据库系统的一个关键特性。

  6.1、什么是锁?

  锁是用来管理对共享文件的并发访问。innodb会在行级别上对数据库上锁。不过innodb存储引擎会在数据库内部其他多个地方使用锁,从而允许对不同资源提供并发访问。例如操作缓冲池中的LRU列表,删除,添加,移动LRU列表中的元素,为了保证一致性,必须有锁的介入。

  6.2、innodb存储引擎中的锁

  6.2.1、锁的类型

  S lock 共享锁 允许事务读一行数据

  X lock 排它锁 允许事务删除或者更新一条数据

  IS lock 意向共享锁 事务想要获得一个表中某几行的共享锁

  IX lock 意向拍他所 事务想要获得一个表中某几行的排它锁

  可以使用 show engine innodb status\G查看 TRANSACTIONS中关于锁的信息。也可以使用 show full processlist查看相关信息。在innodb插件版本以后,可以通过查看INFORMATION—SCHEMA中的INNODB_TRX,INNODB_LOCKS,INNODB_LOCK_WAITS三张表来分析存在的锁问题。

  具体参见 P207

  6.2.2、一致性的非锁定读操作

  一致性非锁定读(consistent nonlocking read)是指innodb通过多版本控制(multi versioning)的方式来读取当前执行时间数据库中行的数据。

  多版本控制是通过快照实现的,快照数据其实就是当前数据之前的历史版本,可能有多个版本。这种技术称为行多版本技术,由此带来的并发控制叫做多半本并发控制(multi version concurrency control,MVCC).

  在Read Committed和Repeatable Read(innodb默认的事务隔离级别)下,innodb存储引擎使用非锁定的一致性读。但是对于快照数据的定义却不同。

  在Read Commited级别,对于快照数据,非一致性读总是读取被锁定行的最新一份快照。

  在Repeatable级别下,对于快照数据,非一致性读总是读取事务开始时的行数据版本。

  6.2.3、SELECT…FOR UPDATE & SELECT…LOCK IN SHARE MODE

  SELECT…FOR UPDATE 可以获得一个X锁。

  SELECT…LOCK IN SHARE MODE 可以获得一个S锁。

  6.2.4、子增长和锁

  对于含有子增长计数器的表进行插入时,会执行”SELECT MAX(auto_inc_col) FROM t FOR UPDATE;”插入操作会更具这个自增长的计数器值加1赋予自增长列。这个实现方式叫做AUTO-INC Locking。这是一种特殊的锁,为了提高并发,它不会在事务执行完才释放,只是在语句执行后立即释放。

  从mysql-5.1.22版本开始,innodb引擎提供了一种轻量级互斥量的自增长实现机制,这种机制大大提高了子增长值插入的性能。并且mysql-5.1.22开始,innodb引擎提供了一个参数

  innodb_autoinc_lock_mode,默认的值为1

  在讨论新的增长方式之前我们需要对自增长实现方式分类:

  INSERT-LIKE:指所有的插入语句,比如 INSERT、REPLACE、INSERT…SELECT、REPLACE…SELECT,LOAD DATA等

  Simple insert:指在插入前就能确定插入行数的语句,包括INSERT、REPLACE,不包含INSERT…ON DUPLICATE KEY UPDATE这类语句。

  Bulk inserts:指在插入前不能确定得到插入行的语句。如INSERT…SELECT,REPLACE…SELECT,LOAD DATA.

  Mixed-mode inserts:指其中一部分是子增长的,有一部分是确定的。

  现在有SIMPLE INSERT、BULK INSERTS、MIXED-MODE INSERTS三种类型的INSERT语句,有AUTO-inc locking(最早的)和轻量级互斥量的自增长两种auto—increment锁。

  innodb_autoinc_lock_mode=0 5.1.22之前的方式,也就是所有类型的insert都用AUTO-inc locking。

  innodb_autoinc_lock_mode=1 这个参数是5.1.22之后出现的也是之后的默认值,对于SIMPLE INSERT,使用轻量级互斥量的锁,对于BULK INSERT,使用AUTO-inc locking,

  innodb_autoinc_lock_mode=2 指不管什么情况都使用轻量级互斥的锁,效率最高,但是复制只能使用row-base replication,因为statement-base replication会出现问题。

  另外就是innodb和myisam的一个区别,innodb下,自增长必须是索引,而且必须是索引的第一个列,不然会报错,myisam不会出现这个问题。

  6.2.5、外键和锁

  innodb中,对于一个外键列,如果没有显示的对这个列加索引,innodb就自动的对其加一个索引。

  6.3、锁的算法

  innodb引擎有三种锁的算法设计:

  Record lock:单个记录上的锁

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

  Next-key lock:Gap lock+Next-key lock锁定一个范围,并锁定记录本身。

  6.4、锁问题

  本来锁问题会导致的是更新丢失、幻读、脏读、不可重复读,但是innodb作者却只写出了三种问题,可能是幻读通过innodb Next-key Lock解决了,作者就没有提及。

  这几个锁问题对应事务隔离的4个安全级别:

  READ UNCOMMITTED(事务隔离最低的级别,有事务隔离就能解决更新丢失,但是存在脏读的问题),

  READ COMMITED(ORACLE和SQL SERVER默认的隔离级别,解决了脏读,但是一个事务多次读取的内容不同,出现了不可重复读的问题),

  READ REPEATABLE(可重复读,innodb引擎的默认事务隔离级别,解决了不可重复读的问题,但是产生了幻读,innodb通过Next-key lock解决了幻读).

  SERIALIZABLE(可串行话,通过强制事务排序解决幻读问题,会降低性能)总的看来innodb默认的 READ REPEATABLE是非常棒的。

  6.5、阻塞