http://hudeyong926.iteye.com/blog/1489929

锁是计算机协调多个进程或者线程并发访问某一资源的机制。在数据库中,除了传统的计算资源(cpu、ram、i/o等)的争用外,数据也是一种供多用户共享的资源。如何保证数据并发访问的一致性、有效性是所有数据库必须解决的一个问题,锁冲突也是影响数据库并发访问性能的一个重要因素。从这个角度上来说,锁对数据库而言尤其重要,也更加复杂。

mysql锁概述

mysql的锁机制比较简单,其显著特点就是不同的存储引擎支持不同的锁机制。

  • MyISAM和MEMORY存储采用的是表级锁(table-level locking)
  • BDB存储引擎采用的是页面锁(page-level locking),但也支持表级锁(已经被innodb取代)
  • InnoDB存储引擎既支持行级锁 也 支持表级锁,默认情况下采用行级锁。

三种锁的概述

  • 表级锁:开销小、加锁快;不会出现死锁。锁定粒度大,发生锁冲突的概率最高,并发率最低。
  • 行级锁:开销大、加锁慢;会出现死锁。锁定粒度最小,发生冲突的概率最低,并发率最高。
  • 页面锁:开销和加锁时间介于表锁和行锁之间;会出现死锁;锁定粒度介于表级锁和行级锁之间,并发率一般。

用途

  • 表级锁:适合以查询为主,只有少量的按索引条件更新的应用,如web应用。
  • 行级锁: 适合有大量按索引条件并发更新少量不同的数据,同事又有并发查询的应用,如一些在线事务处理系统。

MyISAM表锁

MyISAM存储引擎只支持表锁

MyISAM表级锁的模式

  • 表共享读锁(Table Read Lock)
  • 表独占写锁 (Table Write Lock)

MyISAM表的读操作,不会阻塞其他用户对同一表的读请求,但会阻塞对同一表的写请求
MyISAM表的写操作,则会阻塞其他用户对同一表的读和写操作
MyISAM表的读操作与写操作之间,以及写操作之间是串行的,当一个线程获得对一个表的写锁后,只有持有锁的线程可以对表进行更新操作。其他线程的读、写操作都会等待,直到锁被释放为止。

并发插入

MyISAM存储引擎有一个系统变量concurrent_insert,专门用以控制其并发插入的行为,其值分别可以为0、1或2。

  • 当concurrent_insert设置为0时,不允许并发插入。
  • 当concurrent_insert设置为1时,如果MyISAM表中没有空洞(即表的中间没有被删除的行),MyISAM允许在一个进程读表的同时,另一个进程从表尾插入记录。这也是MySQL的默认设置。
  • 当concurrent_insert设置为2时,无论MyISAM表中有没有空洞,都允许在表尾并发插入记录。

可以利用MyISAM存储引擎的并发插入特性,来解决应 用中对同一表查询和插入的锁争用。例如,将concurrent_insert系统变量设为2,总是允许并发插入;同时,通过定期在系统空闲时段执行 OPTIMIZE TABLE语句来整理空间碎片,收回因删除记录而产生的中间空洞。有关OPTIMIZE TABLE语句的详细介绍,可以参见第18章中“两个简单实用的优化方法”一节的内容。

MyISAM的锁调度

前面讲过,MyISAM存储引擎的读锁和写锁是互斥的,读写操作是串行的。那么,一个进程请求某个 MyISAM表的读锁,同时另一个进程也请求同一表的写锁,MySQL如何处理呢?答案是写进程先获得锁。不仅如此,即使读请求先到锁等待队列,写请求后 到,写锁也会插到读锁请求之前!这是因为MySQL认为写请求一般比读请求要重要。这也正是MyISAM表不太适合于有大量更新操作和查询操作应用的原 因,因为,大量的更新操作会造成查询操作很难获得读锁,从而可能永远阻塞。这种情况有时可能会变得非常糟糕!幸好我们可以通过一些设置来调节MyISAM 的调度行为。

  • 通过指定启动参数low-priority-updates,使MyISAM引擎默认给予读请求以优先的权利。
  • 通过执行命令SET LOW_PRIORITY_UPDATES=1,使该连接发出的更新请求优先级降低。
  • 通过指定INSERT、UPDATE、DELETE语句的LOW_PRIORITY属性,降低该语句的优先级。