详解Mysql中的锁机制( 四 )


“脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决 。数据库实现事务隔离的方式,基本可以分为以下两种 。
 

  • 一种是在读取数据前,对其加锁,阻止其他事务对数据进行修改 。
  • 另一种是不用加任何锁,通过一定机制生成一个数据请求时间点的一致性数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取 。从用户的角度,好像是数据库可以提供同一数据的多个版本,因此,这种技术叫做数据多版本并发控制(MultiVersion Concurrency Control,简称MVCC或MCC),也经常称为多版本数据库 。
 
在MVCC并发控制中,读操作可以分成两类:快照读 (snapshot read)与当前读 (current read) 。快照读,读取的是记录的可见版本 (有可能是历史版本),不用加锁 。当前读,读取的是记录的最新版本,并且,当前读返回的记录,都会加上锁,保证其他事务不会再并发修改这条记录 。
在一个支持MVCC并发控制的系统中,哪些读操作是快照读?哪些操作又是当前读呢?以MySQL InnoDB为例:
 
  • 快照读:简单的select操作,属于快照读,不加锁 。(当然,也有例外)
select * from table where ?;
  • 当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁 。
    下面语句都属于当前读,读取记录的最新版本 。并且,读取之后,还需要保证其他并发事务不能修改当前记录,对读取记录加锁 。其中,除了第一条语句,对读取记录加S锁 (共享锁)外,其他的操作,都加的是X锁 (排它锁) 。
select * from table where ? lock in share mode; select * from table where ? for update; insert into table values (…); update table set ? where ?; delete from table where ?; 
数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上 “串行化”进行,这显然与“并发”是矛盾的 。同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读”和“幻读”并不敏 感,可能更关心数据并发访问的能力 。
为了解决“隔离”与“并发”的矛盾,ISO/ANSI SQL92定义了4个事务隔离级别,每个级别的隔离程度不同,允许出现的副作用也不同,应用可以根据自己的业务逻辑要求,通过选择不同的隔离级别来平衡 “隔离”与“并发”的矛盾 。下表很好地概括了这4个隔离级别的特性 。
详解Mysql中的锁机制

文章插图
 
获取InonoD行锁争用情况
可以通过检查InnoDB_row_lock状态变量来分析系统上的行锁的争夺情况:
mysql> show status like 'innodb_row_lock%';
详解Mysql中的锁机制

文章插图
 
如果发现锁争用比较严重,如InnoDB_row_lock_waits和InnoDB_row_lock_time_avg的值比较高,还可以通过设置InnoDB Monitors来进一步观察发生锁冲突的表、数据行等,并分析锁争用的原因 。
InnoDB的行锁模式及加锁方法
InnoDB实现了以下两种类型的行锁 。