http://www.cnblogs.com/xpchild/p/3790139.html

MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构变更的一致性。

MDL锁的加锁模式和源码上的组织上和上一篇blog中MySQL表锁的实现方式一致,都采用了【mutex+condition+queue】来实现并发,阻塞,唤醒的控制。

下面就来看看MDL锁:

1. 重要的数据结构:

     

1. MDL_map

  mdl_map使用hash表,保存了MySQL所有的mdl_lock,全局共享,使用MDL_KEY作为key来表,key=【db_name+table_name】唯一定位一个表。

2. mdl_context

  mdl_context在MySQL为每一个connection创建thd时,初始化一个mdl上下文,保存了当前session请求的mdl信息。

3. MDL_lock

  mdl_lock表示系统的一个mdl锁,所有的mdl request都请求对应的mdl_lock,这个mdl_lock结构保存了两个queue,一个是grant_queue表示拿到lock的请求队列。

  一个是wait_queue表示请求这个mdl_lock的阻塞队列。

4. MDL_wait

  mdl_wait包装了一个mutex和一个condition,提供了所有的加锁,wait,notify操作。

5. MDL_request

  在open table的时候,会init一个request,包含了请求的enum_mdl_type,enum_mdl_duration,MDL_ticket,MDL_key。

下面再看看三个重要的枚举类型:

  enum enum_mdl_namespace { GLOBAL=0,SCHEMA,TABLE,FUNCTION,PROCEDURE,TRIGGER,EVENT,COMMIT,/* This should be the last ! */NAMESPACE_END };

enum enum_mdl_duration {/**Locks with statement duration are automatically released at the endof statement or transaction.*/MDL_STATEMENT= 0,/**Locks with transaction duration are automatically released at the endof transaction.*/MDL_TRANSACTION,/**Locks with explicit duration survive the end of statement and transaction.They have to be released explicitly by calling MDL_context::release_lock().*/MDL_EXPLICIT,/* This should be the last ! */MDL_DURATION_END };

enum enum_mdl_type {MDL_INTENTION_EXCLUSIVE= 0,MDL_SHARED,MDL_SHARED_HIGH_PRIO,MDL_SHARED_READ,MDL_SHARED_WRITE,MDL_SHARED_NO_WRITE,MDL_SHARED_NO_READ_WRITE,MDL_EXCLUSIVE,MDL_TYPE_END};

首先:enum_mdl_namespace 表示mdl_request的作用域,比如alter table操作,需要获取TABLE作用域。

然后:enum_mdl_duration 表示mdl_request的持久类型,比如alter table操作,类型是MDL_STATEMENT,即语句结束,就释放mdl锁。又比如autocommit=0;select 操作,类型是MDL_TRANSACTION,必须在显示的commit,才释放mdl锁。

最后:enum_mdl_type 表示mdl_request的lock类型,根据这个枚举类型,来判断是否兼容和互斥。

2. 测试

下面根据一个测试,看一下加锁,释放,阻塞的过程,已经主要的函数调用栈:

  session1:            session2:

    set autocommit=0;        alter table pp add name varchar(100):

    select * from pp;

2.1 创建connection过程中,初始化mdl_context.

  函数调用:

    handle_connections_sockets

      MDL_context::init: 每一个connection对应一个mdl_context

2.2 初始化mdl_request

  函数调用:

    parse_sql

      st_select_lex::add_table_to_list
        MDL_request::init

  说明: 在session1的过程中,创建的mdl_request:

      mdl_namespace=MDL_key::TABLE,

      db_arg=0x8c7047c8 "xpchild",

      name_arg=0x8c7047d0 "pp", 
      mdl_type_arg=MDL_SHARED_READ,

      mdl_duration_arg=MDL_TRANSACTION

2.3 加锁

acquire_lock:

if (lock->can_grant_lock(mdl_request->type, this)){lock->m_granted.add_ticket(ticket);mysql_prlock_unlock(&lock->m_rwlock);m_tickets[mdl_request->duration].push_front(ticket);mdl_request->ticket= ticket;}

说明:首先进行兼容性判断,如果兼容,那么就把ticket加入到队列中,加锁成功。

  函数调用栈

   open_and_lock_tables

    open_table

1. 排他锁使用
  lock_table_names
  MDL_context::acquire_locks
2. 共享锁使用
  open_table_get_mdl_lock
  MDL_context::try_acquire_lock

2.4 阻塞

  下面进入session2. 因为session1拿到了pp表的share读锁,但session2的alter操作的mdl_request类型是:MDL_INTENTION_EXCLUSIVE,兼容性判断是互斥,所以ddl被阻塞。

while (!m_wait_status && !thd_killed(thd) &&wait_result != ETIMEDOUT && wait_result != ETIME){wait_result= mysql_cond_timedwait(&m_COND_wait_status, &m_LOCK_wait_status,abs_timeout);}

说明:上面的这段代码,session2进入阻塞状态,等待超时或者mdl_wait中的条件变量。

2.5 唤醒

session1进行提交动作,commit。 然后session1 release mdl_lock,最后wake up session2.  session 2完成alte操作。

    MDL_context::release_lock();lock->remove_ticket();    reschedule_waiters();while ((ticket= it++)){if (can_grant_lock(ticket->get_type(), ticket->get_ctx())){if (! ticket->get_ctx()->m_wait.set_status(MDL_wait::GRANTED))MDL_wait::set_status();mysql_cond_signal(&m_COND_wait_status);

说明: commit操作,释放session 1持有的mdl事务锁,然后遍历wait队列,判断兼容性测试,最后wakeup session2.

总结: 根据上面的测试,我们看到,mdl的机制和表锁的机制基本一致性,但从上面的测试和源码的设计上,也看到MySQL表锁,mdl锁令人蛋疼的地方。

3. 蛋疼的锁

下面简单介绍下MySQL锁令人蛋疼的两个地方:

1. 事务开始begin transaction的位置

  •   MySQL的设计:在设置的autocommit=0;read_commited的时候,无论session的第一条语句是select还是dml,都开始一个事务,然后直到commit,所持有的MDL锁也一直维持到commit结束。
  •   Oracle的设计:在session的第一条更新语句发起时,才创建transaction,在读多的系统上,减少了阻塞的发生可能性。特别是在开发人员发起select语句时,认为没有更新,就不再commit。但在MySQL上,发起select语句,而忘记commit,是非常危险的。

2. ddl语句阻塞

  •   MySQL的设计:ddl语句发起时,如果无法获取排他锁,那么ddl将进入阻塞状态,但由于是queue的设计,就阻塞了后续所有的dml和selec操作,在高并发系统上,可能会引起雪崩。
  •       Oracle的设计:在oracle 11g之前,ddl语句是fast fail的,不进入阻塞状态,所以繁忙的表进行ddl操作时,经常遇到的错误:ORA-00054: resource busy。但在11g之后虽然可以进行阻塞,并提供了ddl_time_out这样的参数进行控制,但在高并发的系统上,运维的操作依然不采用,而是fast fail。

后话:

  这里可以参照oracle的设计进行改良,ddl语句阻塞相对改源码来说,比较简单。而事务开始的位置,牵涉到mvcc和事务隔离级别,改动会比较大。

MySQL锁系列3 MDL锁相关推荐

  1. mysql mdl锁_MySQL锁系列3 MDL锁

    MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构变更的一致性. MDL锁的加锁模式和源码上的组织上和上一篇blog中MySQL表锁的实现方式一致 ...

  2. mysql mdl 锁_MySQL锁系列3 MDL锁

    MySQL为了保护数据字典元数据,使用了metadata lock,即MDL锁,保证在并发的情况下,结构变更的一致性. MDL锁的加锁模式和源码上的组织上和上一篇blog中MySQL表锁的实现方式一致 ...

  3. 看完就明白锁系列之自旋锁

    https://cloud.tencent.com/developer/article/1519618

  4. 【华为云技术分享】华为云MySQL新增MDL锁视图特性,快速定位元数据锁问题

    MDL锁(Metadata Lock),即元数据锁.元数据指的是描述数据的数据,对数据及信息资源的描述性信息,在数据库中元数据即数据字典信息,包括db,table,function,procedure ...

  5. mysql数据库锁MDL锁的解释

    1.背景 在我们系统中有一张表它的查询概率非常高.最近有个需求,需要对这个表增加一个字段,然而在增加字段的时候发现系统中有多个业务出现了超时操作,那么这个是什么原因导致的呢?经过查阅资料发现是数据库的 ...

  6. mysql三锁,mysql锁机制之表锁(三)

    顾名思义,表锁就是一锁锁一整张表,在表被锁定期间,其他事务不能对该表进行操作,必须等当前表的锁被释放后才能进行操作.表锁响应的是非索引字段,即全表扫描,全表扫描时锁定整张表,sql语句可以通过执行计划 ...

  7. 有了MDL锁视图,业务死锁从此一目了然

    当多用户共同存取数据时,数据库中就会产生多个事务同时存取同一数据的情况.若不控制这种并发操作,数据库的一致性就会被破坏.这种情况下,加锁是实现数据库并发控制的关键技术. 举个例子,加锁后事务就对该数据 ...

  8. 锁9---自旋锁 VS 适应性自旋锁

    锁9-自旋锁 VS 适应性自旋锁 ************ 如有侵权请提示删除 *************** 文章目录 锁9---自旋锁 VS 适应性自旋锁 自旋锁 1.概念: 2.提出背景 3.自 ...

  9. 数据库周刊59丨GaussDB(for openGauss)开放商用;人大金仓保障冬奥会演练顺利完成;MDL锁导致的MySQL问题分析;PG日志使用手册;达梦表空间查询;数据库笔试题面试题集……

    热门资讯 1.openGauss 上线华为云正式商用 - GaussDB(for openGauss) [摘要]近日,GaussDB(for openGauss)已于华为云官网全面开放商用.该产品是华 ...

最新文章

  1. python减小内存占用_如何将Python内存占用缩小20倍?
  2. 6.python探测Web服务质量方法之pycurl模块
  3. 过年回家应对七大姑八大姨,程序猿绝了!
  4. 5界面怎么做窗帘拉动的效果_别让土味窗帘毁了你的家
  5. 搜狐视频开放平台的申请使用方法
  6. cuda Device Management
  7. 通过计算机名访问linux
  8. 杭电计算机2010年笔试真题详解
  9. 论文笔记_S2D.48_2017-IEEE RAL_单视图和多视图深度融合
  10. gc java 单核_JAVA应用性能监控之JVM层GC调优
  11. JDK+Eclipse安装
  12. 顺序表的基本操作代码实现
  13. CUDA-NPP图像和视频处理
  14. 8051单片机的C语言程序设计
  15. 编程视频资源教程汇总
  16. 证券交易系统术语介绍
  17. 创建github或者gitee(国内版github)账户
  18. 叮咚买菜拟赴美上市 官网域名为杂米域名100.me
  19. 作业十一:安装关系型数据库MySQL
  20. 美光Crucial BX300 SSD评测 | 揭穿不实报道,惊不惊喜?

热门文章

  1. Using the itemDoubleClick event to open nodes in a Flex Tree control
  2. JavaScript-在当前显示区范围内实现点不到的小方块
  3. (林雷看来13):功能优先,发展和重建同步,业绩后
  4. EIGRP传递默认路由方法总结
  5. T-SQL象数组一样处理字符串、分割字符串
  6. 高中理科不好学计算机,高一理科很差但想学理咋办
  7. 使用 AppFuse 快速构建 J2EE 应用
  8. K02-01通过简单exe介绍pro基本配置
  9. String StringBuffer StringBuilder的异同
  10. 极品五笔管理员能用,普通用户无法使用