http://blog.csdn.net/taozhi20084525/article/details/19545231

一、知识准备之隐式锁

参考:http://www.uml.org.cn/sjjm/201205302.asp

Innodb 实现了一个延迟加锁的机制,来减少加锁的数量,在代码中称为隐式锁(Implicit Lock)。隐式锁中有个重要的元素,事务ID(trx_id)。隐式锁的逻辑过程如下:

A. InnoDB的每条记录中都一个隐含的trx_id字段,这个字段存在于簇索引的B+Tree中。

B. 在操作一条记录前,首先根据记录中的trx_id检查该事务是否是活动的事务(未提交或回滚)。如果是活动的事务,首先将隐式锁转换为显式锁(就是为该事务添加一个锁)。

C. 检查是否有锁冲突,如果有冲突,创建锁,并设置为waiting状态。如果没有冲突不加锁,跳到E。

D. 等待加锁成功,被唤醒,或者超时。

E. 写数据,并将自己的trx_id写入trx_id字段。Page Lock可以保证操作的正确性。

二、具体代码

转自:《InnoDB SMO & Page Extent & Lock & Latch》 by 何登成

InnoDB 的 insert 操作,对插入的记录不加锁,但是此时如果另一个线程进行当前读,类似与以下的用例,session 2 会锁等待 session 1,那么这是如何实现的呢?

session 1:                			session 2:
set autocommit = ‘ off ’;
insert into c values (11, ’ aaa’);
select * from c where c1 = 11 lock in share mode;

下面是 session 2 的源码跟踪流程:

row_search_for_mysql();
sel_set_rec_lock();

// 将记录上的 implicit 锁转换为 explicit 锁
lock_rec_convert_impl_to_expl();
// 查询当前记录上是否存在 implicit 锁
// 1. 必须已经持有了 kernel mutex
// 2. 获取记录上的 DB_TRX_ID 系统列,获取事务 ID
// 3. 根据事务 ID,判断当前事务是否为活跃事务
// 4. 若为活跃事务,则返回此活跃事务对象
impl_trx = lock_clust_rec_some_has_impl(rec, index, offsets);
ut_ad(mutex_own(&kernel_mutex));
trx_id = row_get_rec_trx_id();
trx_is_active(trx_id);
// 判断返回事务,是否含有 explicit 锁;若有,直接返回;否则将
// implicit 锁转化为 explicit 锁;由 session 2 完成 session 1 insert 记录的加锁
lock_rec_has_expl(impl_trx);
// 当前 session 1 不存在 explicit 锁,因此直接创建一个锁,锁模式为
// LOCK_REC | LOCK_X | LOCK_REC_NOT_GAP
// 由于 insert 记录上不可能有其他锁,因此转化直接成功,X 锁加上
lock_rec_add_to_queue();
// 完成 session 1 的 insert 操作的 implicit 到 explicit 锁转化之后,此时可以加 session 2
// 的 scan S 锁,但是会等待 session 1 放锁
lock_rec_lock();

备注:Insert 不加锁,或者说是 Implicit Lock 的意义其实十分重大。从前面介绍的 Lock 结构中,我们可以分析出,其实 InnoDB 的一个锁结构的开销是比较大的。 或者说InnoDB 锁一条记录的开销,与锁一个页面中所有记录的开销是一样的。而 Insert 通过 Implicit 方式加锁,极大的减轻了 Insert 时的锁模块开销,对于 InnoDB 支持并发 Insert 操作,是一个极大的提升。

三、隐式锁的重要问题——check Duplicate

转自:《InnoDB SMO & Page Extent & Lock & Latch》 by 何登成

进一步参考: Innodb锁系统 Insert/Delete 锁处理及死锁示例分析 http://fan0321.iteye.com/blog/1984364

这里主要看聚集索引的check duplicate。check duplicate也就是保证在隐式锁情况下,多个事务的insert是如何保证索引的unique的。

1、聚集索引check duplicate

ha_innobase::write_row();

row_ins_index_entry_low();
// 做 search path,将 cursor 定位到第一个小于等于插入值的位置
btr_cur_search_to_nth_level(PAGE_CUR_LE);
// cursor 是 binary search 之后在叶节点定位的 insert 位置
// 判断 binary search 的结果,当前记录与待 insert 记录有几个相同的列
// 若相同列取值的列数量(cursor->low_match),超过当前索引的唯一键值数量,
// 则可能存在唯一性键值冲突
row_ins_duplicate_error_in_clust(cursor, entry, thr);
n_unique = dict_index_get_n_uniques();
if (cursor->low_match >= n_unique)
// 对 cursor 对应的已有记录加 S 锁(可能会等待),保证记录上的操作,包括:
// Insert/Update/Delete 已经提交或者回滚
// S 锁已经可以保证其他事务的 insert 操作不能进行,因为在真正
// insert 操作进行时,会尝试对 下一个record加 X 锁,详见下一章节分析
row_ins_set_shared_rec_loc(LOCK_S);
lock_clust_rec_read_check_and_lock();
// 判断 cursor 对应的记录上是否存在 implicit 锁(有活跃事务)
// 若存在,则将 implicit 锁转化为 explicit 锁
lock_rec_convert_impl_to_expl();
lock_rec_lock(); //如果上面的隐式锁转化成功,此处加S锁将会等待,直到活跃事务释放锁。
// S 锁加锁完成之后,可以再次做判断,最终决定是否存在 unique 冲突
// 1. 判断 insert 记录与 cursor 对应的记录取值是否相同
// 2. 二级唯一键值锁引,可以存在多个 NULL 值
// 3. 最后判断记录的 delete_bit 状态,判断记录是否被删除提交
row_ins_dupl_err_with_rec();
cmp_dtuple_rec_with_match();
return !rec_get_deleted_flag();

注意:S锁加锁成功之时,活跃事务应当提交或回滚并释放锁;但不管是提交还是回滚,cursor指向的record仍然存在,可能会有delete标志(发生回滚)。

2、辅助索引check duplicate

a、聚簇索引 primary key 是唯一的;非聚簇唯一索引,其索引也是唯一的。
b、若 insert 记录与聚簇索引项完全相同,并且聚簇索引项为删除项,则直接将其删除标记设置为 0,并在删除项上做 update。
c、若 insert 记录与非聚簇唯一索引项键值完全相同, 并且非聚簇索引项为删除项, 此时并不一定修改项状态,还需要判断两者对应的 primary key 是否相同,若 primary key 也相同,则重用项;否则,插入新项。
d、聚簇索引中,相同 primary key 取值的项,最多只有一项,不可能存在多项。
e、非聚簇唯一索引,索引键值相同的项可能有多项,但是这些项,其 primary  key 是不同的;而且,这些项,只有一个是有效项,其他项都为已删除的提交项。
f、聚簇索引的唯一性检查,只需要检测 insert 对应的记录即可,因为只有一项;非聚簇唯一索引的唯一性检测,需要向后检查多条键值相同记录

 
 

innodB的隐式锁的更多相关文章

  1. Java并发之显式锁和隐式锁的区别

    Java并发之显式锁和隐式锁的区别 在面试的过程中有可能会问到:在Java并发编程中,锁有两种实现:使用隐式锁和使用显示锁分别是什么?两者的区别是什么?所谓的显式锁和隐式锁的区别也就是说说Synchr ...

  2. java里的锁总结(synchronized隐式锁、Lock显式锁、volatile、CAS)

    一.介绍 首先, java 的锁分为两类: 第一类是 synchronized 同步关键字,这个关键字属于隐式的锁,是 jvm 层面实现,使用的时候看不见: 第二类是在 jdk5 后增加的 Lock ...

  3. innodb 源码分析 --锁

    innodb引擎中的锁分两种 1)针对数据结构, 如链表 互斥锁 读写锁 http://mysqllover.com/?p=425 http://www.cnblogs.com/justfortast ...

  4. 深入理解Java内置锁和显式锁

    synchronized and Reentrantlock 多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两 ...

  5. java 并发多线程显式锁概念简介 什么是显式锁 多线程下篇(一)

    目前对于同步,仅仅介绍了一个关键字synchronized,可以用于保证线程同步的原子性.可见性.有序性 对于synchronized关键字,对于静态方法默认是以该类的class对象作为锁,对于实例方 ...

  6. 显式锁(二)Lock接口与显示锁介绍

    一.显式锁简介    显式锁,这个叫法是相对于隐式锁synchronized而言的,加锁和解锁都要用户显式地控制.显示锁Lock是在Java5中添加到jdk的,同synchronized一样,这也是一 ...

  7. 显式锁(三)读写锁ReadWriteLock

    前言:   上一篇文章,已经很详细地介绍了 显式锁Lock 以及 其常用的实现方式- - ReetrantLock(重入锁),本文将介绍另一种显式锁 - - 读写锁ReadWriteLock.    ...

  8. 显式锁(四)Lock的等待通知机制Condition

       任意一个Java对象,都拥有一组监视器方法(定义在根类Object上),主要包括:wait( ).wait(long timeout).notify().notifyAll()方法:这些方法与关 ...

  9. 深入理解java内置锁(synchronized)和显式锁(ReentrantLock)

    多线程编程中,当代码需要同步时我们会用到锁.Java为我们提供了内置锁(synchronized)和显式锁(ReentrantLock)两种同步方式.显式锁是JDK1.5引入的,这两种锁有什么异同呢? ...

随机推荐

  1. Spring3 整合Quartz2 实现定时任务

    一.Quartz简介 Quartz是一个由James House创立的开源项目,是一个功能强大的作业调度工具,可以计划的执行任务,定时.循环或在某一个时间来执行我们需要做的事,这可以给我们工作上带来很 ...

  2. 线性时间内确定T[0:n]是否有一个主元素

    设T[0:n-1]是n 个元素的数组.对任一元素x,设S(x)={ i | T[i]=x}.当| S(x) |>n/2 时,称x 为T 的主元素.设计一个算法,确定T[0:n-1]是否有一个主元 ...

  3. Delphi 调用外部程序并等待其运行结束

    转自:http://blog.csdn.net/xieyunc/article/details/4140620   如何让Delphi调用外部程序并等待其运行结束 1. uses     Window ...

  4. 使用Go开发一个简单的服务器程序

    最近有个小项目,需要一个简单的后台程序来支撑,本来想用Nodejs来做,但是由于本人js一直很菜,并且很讨厌callback,虽然我也很喜欢异步模型,但我一直都觉得JS是反人类的.后台就用了go处理, ...

  5. NServiceBus教程-持久化配置

    当配置在NServiceBus v5持久性,秩序是非常重要的.最后赢得持久性配置选项.我们看看一些例子. 示例1 在本例中最后一个配置选项将会覆盖前面的所有选项. v5.2 v5.0 编辑 var c ...

  6. 第二百零四天 how can i 坚持

    我应该不会看错吧.最近媒体热炒小米衰落了,有必要那么大张旗鼓的报道吗?小米.华为,坚决看好小米.感觉华为品牌有些杂乱,在走三星的老路,小米有些苹果的影子,但是,多了个互联网.互联网... 未来孰优孰劣 ...

  7. 第二百一十八天 how can I 坚持

    真的是自以为是吗?或许是我想太多. 今天下雪了,2015年入冬以来的第一场雪,好冷. 又是一周. 睡觉吧,明天老贾生日. 没啥了,中午有点肚子疼,冬天了要注意.

  8. Linux查看系统信息命令总结

    系统 # uname -a               # 查看内核/操作系统/CPU信息 # head -n 1 /etc/issue   # 查看操作系统版本 # cat /proc/cpuinf ...

  9. WebSphere 集群环境下配置 Quartz集群

    转载:http://hyamine.iteye.com/blog/397708 1. websphere工作管理器引用 WEB-INF/ibm-web-bnd.xmi <?xml version ...

  10. ecshop读写分离

    1.配置文件设置 $db_name = "ecshop"; $prefix = "ecs_"; $timezone = "Europe/Berlin& ...