注册 登录  
 加关注
查看详情
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

篝火旁的匠人

篝火旁的匠人,开始了思考……

 
 
 

日志

 
 

InnoDB行锁需要注意的一些问题  

2009-07-16 21:29:53|  分类: 技术 |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

在4月28日的学习心得交流讲座中,通过大家提出疑惑、一起探讨和总结,搞明白了很多问题。现在就把大家对InnoDB加锁的看法做下总结。

为了更好的说明理论,通过适当的例子进行论证,现在假定建立InnoDB表user:

CREATE  TABLE  user(

id int,

name varchar(20),

primary key(id)

)ENGINE = 'InnoDB';

插入数据:

INSERT  INTO  user VALUES(1,'Kobe'),(2,'James'),(4,'Paul'),(8,'Yao');

当前锁隔离级别是:REPEATABLE READ

并且set autocommit = 0;

 

1、InnoDB行锁是通过给索引上的索引项加锁实现的,这就意味着:只有通过索引条件检索数据,InnoDB才使用行级锁,否则,InnoDB将使用表锁。比如:

        Session A                                  Session B

BEGIN;                                  BEGIN;

SELECT * FROM user WHERE name = 'Kobe' 

FOR UPDATE;

+----+-------+

| id  | name |

+----+-------+

| 1  | Kobe |

+----+-------+

1 rows in set (0.00 sec)

        SELECT * FROM user WHERE id = 2 

LOCK IN SHARE MODE;

(waiting....)

由于表项name并不是索引,所以使用name作为检索数据条件,会对整表加锁,故在session B中的select语句会出现等待。

 

2、对于next-key lock的理解。This is a combination of a record lock on the index record and a gap lock on the gap before the index record。所以next-key lock包含索引的记录锁以及该索引前的间隙锁。

或许大家对定义不是十分清楚,下面就通过表user来说明next-key lock锁的范围,以及所带来的一些问题。对于当前的user表,可能包含的next-key lock如下('[' 或者']'表示包括索引,'('或者')'则不包括索引,通过范围表达式来直观表示next-key lock对哪些范围进行了加锁):

(-,1];

(1,2];

(2,4];

(4,8];

(8,+∞)

通过上面的范围表达式,就不难理解查询语句:

SELECT * FROM user WHERE id < 7 FOR UPDATE;

对哪些范围进行了加锁,主要包括:

(-,1];(1,2];(2,4];(4,8]

请注意的是对索引8也进行了加锁,主要原因是查询条件包含了索引4到索引8之间的间隙,由于该语句加的是next-key lock,故包含了(4,8],所以包含了索引8。

 

但是对于查询语句:

SELECT * FROM user WHERE id > 4 FOR UPDATE;

会对哪些范围加锁呢,其范围主要包括:

(4,8];(8,+∞)

请注意该语句没有对索引4加锁next-key lock包含索引的记录锁以及该索引的间隙锁。

通过以上两个例子,大家很明显的看出next-key lock锁的范围,并且注意到在查询条件中'<'和'>'的差别。

 

3、对行索引(record)加锁,锁的类型由具体的SQL语句而定;但是对于行索引之间的间隙(gap)加锁,不管SQL语句加哪种锁,结果都是加共享锁(share lock)。比如:

示例1):

执行语句:

SELECT * FROM user WHERE  id = 3 FOR UDPATE;

由于表中并不存在id为3的记录,所以该条语句锁的是索引2和索引4之间的间隙,但是加的是共享锁。

示例2):

        Session A                           session B

BEGIN;                              BEGIN;

SELECT * FROM user WHERE id < 6 

FOR UPDATE;

+----+-------+

| id  | name |

+----+-------+

| 1  | Kobe |

| 2  | James |

| 4  | Paul  |

+----+-------+

3 rows in set (0.00 sec)

   SELECT * FROM user WHERE id = 3 

   FOR UPDATE;

   Empty set (0.00 sec)

ROLLBACK;                          ROLLBACK;

之所以在session B中执行select语句后,没有出现等待,是因为对间隙加的是共享锁。

 

4、当语句INSERT INTO ...失败,出现duplicate-key(重复键)错误,InnoDB引擎除了提示错误外,还会对该行记录加共享锁。比如

mysql>INSERT INTO user  VALUES(1,'Yao');

ERROR 1062 (23000): Duplicate entry '1' for key 1

但是此刻会对索引1加共享锁。

  评论这张
 
阅读(221)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018