MySQL锁系列2 表锁
http://www.cnblogs.com/xpchild/p/3789068.html
上一篇介绍了MySQL源码中保护内存结构或变量的锁,这里开始介绍下MySQL事务中的表锁。
注1: 在表锁的实现上面,使用【mutex+condition+queue】的结构实现并发,阻塞,唤醒的表锁功能。
注2: 本文进行的一些实验,重要的配置项:
1. autocommit=0
2. tx_isolation=read-commited
3. engine=innodb
1. MySQL加锁的顺序:

这里包括了一个sql在执行的过程中,包括commit,所添加和释放跟事务相关的锁以及加不同锁的加锁顺序,这一篇先重点介绍一下MySQL的表锁。
2. MySQL的表锁
注:通过测试看到,MySQL的表锁,是落入innodb层的代码中实现的。
2.1 重要的数据结构
struct st_thr_lock_info
struct st_thr_lock_data
struct st_thr_lock
通过这三个主要的struct,来实现表锁,这三者之间的关系是:

说明:
1. 每一张表,在打开的时候,创建一个innobase_share对象,并初始化一个st_thr_lock结构进行关联,所有请求这个表的表锁,需要关联这个对象
2. 每一次sql请求,在open table的过程中,会创建一个table,handler对象,这个handler会初始化一个st_thr_lock_data,关联st_thr_lock结构。
2.2 测试
1. 测试用例:
session1: session2:
lock table pp write; select * from pp;
2. 测试的主要步骤:
1. open table
2. lock table
3. 表锁相关的case场景:
1. 加锁
2. 阻塞
3. 唤醒
2.2.1 open table
open table的细节也可以参考:open table
这里主要介绍innodb层在open table时创建的主要的数据结构:
1. innobase_share
innodb层表示一个table的结构,包括初始化一个thr_lock,所有请求表锁的关联结构
2. ib_table
innodb层表示一个table的统计信息
3. handler
提供给sever层table的结构,所有对innodb层的操作,都通过handler,并初始化了一个st_thr_lock_data
主要函数调用栈:
open_table
open_table_from_share
ha_innobase::open: get_share/thr_lock_init/thr_lock_data_init
1. 在第一次open 这个表时,创建innobase_share, 初始化THD_LOCK, 初始化 ib_table
2. 初始化handler,初始化THD_LOCK_DATA。
说明:
1. 所有的innobase_share结构,保存到一个全局hash表中:innobase_open_tables,全局共享
2. open结束后,创建完成的所有的相关的数据结构关联图如下:

解释: 红色的部分是表锁的关键结构,mutex用于保护thr_lock queue结构,所有的加锁,wait 锁,线层结构都需要进入thr_lock中的queue,一共有四个queue: read,read_wait, write, write_wait.
每一个handler都关联thread的一个condition,所有的wait,wakeup,都使用这个condition来完成,这样可以实现定向唤醒,避免广播。
2.2.2 lock table
session1:请求的lock_type = TL_WRITE
session2:请求的lock_type = TL_READ
一共的thr_lock_type有14种,分别是:

tl_ignore=-1,
tl_unlock,
tl_read_default,
tl_read,
tl_read_with_shared_locks,
tl_read_high_priority,
tl_read_no_insert,
tl_write_allow_write,
tl_write_concurrent_insert,
tl_write_delayed,
tl_write_default,
tl_write_low_priority,
tl_write,
tl_write_only

主要函数调用栈:
mysql_lock_tables:把所有table的thr_lock_data放到MYSQL_LOCK的结构中。
get_lock_data
ha_innobase::store_lock:把之前的lock清理掉。换成目前要请求的lock类型。
thr_multi_lock:请求锁表
thr_lock: 单个thr_lock_data锁表
下面看下关键的三个步骤:锁表,阻塞,唤醒
锁表:session 1
session1 使用lock write来加锁,这里加的是排他锁,thr_lock结构上没有其他锁,这里会加成功,
主要的代码:
mysql_mutex_lock(&lock->mutex); 锁住这个表的mutex,开始进入这个表锁的串行操作。
lock_type=TL_WRITE
(*lock->write.last)=data; /* Add to running FIFO */
data->prev=lock->write.last;
statistic_increment(locks_immediate,&THR_LOCK_lock); 累计locks_immediate计数
阻塞:session 2
session 2申请pp表的read表锁,但session1已经获得的排他锁,这里会阻塞,并wait 这个线程的condition。
wait_for_lock(wait_queue, data, 0, lock_wait_timeout)
statistic_increment(locks_waited, &THR_LOCK_lock); 累计locks_waited计数
(*wait->last)=data; /* Wait for lock */ 加入wait队列
data->prev= wait->last;
wait->last= &data->next;
mysql_cond_timedwait(cond, &data->lock->mutex, &wait_timeout); 等待这个thread的condition
这里的condition要注意,是THD结构中的condition,线程的阻塞,不管是因为什么原因,只需要一个condition就可以完成,没有必要对于不同的锁等待,创建不同的condition。
唤醒:session 1 unlock。
session1:使用unlock tables操作。
/* Unlock lock and free next thread on same lock */
thr_unlock:
wake_up_waiters(lock); 唤醒等待同一个lock的thread,这里需要判断lock请求的兼容模式,并且因为使用queue保存了请求wait队列,防止了饿死。
mysql_cond_signal(cond);
注意:
对于innodb来说,不论autocommit的设置如何,每一个dml select结束后,都使用thr_unlock释放掉了表锁,这里的理解是:innodb倾向使用行级锁来支持事务,对于保护表metadata信息,则使用MDL来保护,所以innodb对于表锁来说,并没有使用意愿。
后话:
对于上面的测试,大家可以试一下,先操作session2. 后操作session1。结果是一样的,都是阻塞,但是这里阻塞在什么锁上,完全不同。
简略测试一下:
session 2: select * from pp :
open
获取mdl锁,
获取表锁,
执行结束
释放表锁: (因为autocommit=0,这里并没有释放mdl锁)
session 1: lock table pp write
open
获取mdl排他锁: (阻塞:因为session2没有释放mdl锁,所以这里阻塞)
大家可以看到,这里是因为ddl需要拿到mdl排他锁,而阻塞。
下一篇blog,我们就来看看mdl锁的情况。
MySQL锁系列2 表锁的更多相关文章
- mysql 开发进阶篇系列 13 锁问题(关于表锁,死锁示例,锁等待设置)
一. 什么时候使用表锁 对于INNODB表,在绝大部分情况下都应该使用行锁.在个别特殊事务中,可以考虑使用表锁(建议). 1. 事务需要更新大部份或全部数据,表又比较大,默认的行锁不仅使这个事务执行效 ...
- Mysql InnoDB 是IOT表 锁基于索引
</pre>Mysql InnoDB 是IOT表 锁基于索引<pre>
- MySQL 避免行锁升级为表锁——使用高效的索引
文章目录 普通索引 属性值重复率高 属性值重复率低 小结 众所周知,MySQL 的 InnoDB 存储引擎支持事务,支持行级锁(innodb的行锁是通过给索引项加锁实现的).得益于这些特性,数据库支持 ...
- mysql的innodb 引擎 表锁与行锁
innodb 引擎 行锁与表锁 行锁与表锁是基于索引来说的(且索引要生效) 不带索引 (表锁)要全表扫描 1. 执行select @@autocommit; 查看结果 0是不自动提交事务,1是自动提交 ...
- MySQL 啥时候用表锁,啥时候用行锁?
大家好,我是树哥. MySQL Innodb 的锁可以说是执行引擎的并发基础了,有了锁才能保证数据的一致性.众所周知,我们都知道 Innodb 有全局锁.表级锁.行级锁三种,但你知道什么时候会用表锁, ...
- MySQL锁系列3 MDL锁
http://www.cnblogs.com/xpchild/p/3790139.html MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构 ...
- Mysql MyISAM与InnoDB 表锁行锁以及分库分表优化
一. 两种存储引擎:MyISAM与InnoDB 区别与作用 1. count运算上的区别: 因为MyISAM缓存有表meta-data(行数等),因此在做COUNT(*)时对于一个结构很好的查询是不需 ...
- MySQL性能优化(七·上)-- 锁机制 之 表锁
前言 数据库的锁主要用来保证数据的一致性的.MyISAM存储引擎只支持表锁,InnoDB存储引擎既支持行锁,也支持表锁,但默认情况下是采用行锁. 一.锁分类 1.按照对数据操作的类型分:读锁,写锁 读 ...
- mysql锁机制之表锁(三)
顾名思义,表锁就是一锁锁一整张表,在表被锁定期间,其他事务不能对该表进行操作,必须等当前表的锁被释放后才能进行操作.表锁响应的是非索引字段,即全表扫描,全表扫描时锁定整张表,sql语句可以通过执行计划 ...
随机推荐
- NEUOJ711 异星工厂 字典树+贪心
题意:你可以收集两个不相交区间的权值,区间权值是区间异或,问这两个权值和最大是多少 分析:很多有关异或求最大的题都是利用01字典树进行贪心,做这个题的时候我都忘了...最后是看别人代码的时候才想起来这 ...
- C++实现网格水印之调试笔记(六)——补充
调用matlab生成的网格水印特征向量矩阵 从文件中读取的原始网格的特征向量矩阵 好吧,之前得出的结果不正确是因为代码写错了.因为实现论文中的提取方案时代码写错了,自己想了另外一个方法,结果方向两者在 ...
- C++实现网格水印之调试笔记(二)
整理了一下要实现的论文Watermarking 3D Polygonal Meshes in the Mesh Spectral Domain,步骤如下: 嵌入水印 à 提取水印 à 优化(网格细分) ...
- res/raw和assets的 区别
res/raw和assets的相同点: 两者目录下的文件在打包后会原封不动的保存在apk包中,不会被编译成二进制. res/raw和assets的不同点: 1.res/raw中的文件会被映射到R.ja ...
- .net中的"异步"-手把手带你体验
周二刚过,离5.1小长假还有那么一阵,北京的天气已经开始热起来了.洗完澡,突然想起博客园一位大哥暂称呼元哥吧,当时我写了一篇windows服务的安装教程(http://www.cnblogs.com/ ...
- 第三百零五天 how can I 坚持
今天去E世界拿抽的奖品,白去了 一趟,结果已经被拿过去了,明天还得去另一个地拿,太折腾了,今天走了1万4千多步. 哎,徐斌啊,出去见个面,这个折腾啊,受不了,想干他.开个玩笑. 黄东月,为什么打字莫名 ...
- Window下开发React-Native Android步骤
1.安装Android开发环境 下载并安装JDK 下载并安装Android SDK, Android NDK 启动SDK下面的SDK Manager.exe,安装相关SDK Platform-tool ...
- 转】Maven学习总结(四)——Maven核心概念
原博文出自于: http://www.cnblogs.com/xdp-gacl/p/4051819.html 感谢! 一.Maven坐标 1.1.什么是坐标? 在平面几何中坐标(x,y)可以标识平面中 ...
- Homework-10 the Enhanced Version
经过一周对于JavaScript HTML语言等相关知识的学习,我终于基本完成了作业的要求,也是实现了我原先计划的第二部,推出了加强版的Homework-10 他由3个HTML组成,JS脚本直接选择嵌 ...
- [iOS UI进阶 - 4.0] 涂鸦app Demo
A.需求 1.超简易画图,只有一种画笔 2.清屏功能 3.回退功能 4.保存功能 5.使用了cocos2D code source: https://github.com/hellovoidwor ...