前言:元数据锁不是锁定数据,而是锁定描述数据的元数据信息。就像很多装修工人(工作线程)在室内(对象上)装修(操作),不能有其他工人(线程)把屋子拆了(表删除了)。

MySQL 为了数据一致性使用元数据锁来管理并发访问数据库中的对象。元数据锁不仅仅作用于表上,同时对存储程序(schemas,procedure,function,triggers,events)以及表空间都适用。

译者废话:也就是说,为防止一个线程在插入一条记录,另一个线程删了表。所以在第一个线程在写入时,还要有元数据锁。

性能数据库(Performance Schema)中的 metadata_lock 表记录了关于元数据锁的信息。其中可以看到哪个会话持有锁、因为等待锁被堵塞等等。关于这个表的详细信息请看。

元数据锁定会涉及一些开销,随着查询量的增加而增加。 元数据争用会增加,多个查询尝试访问相同对象。
元数据锁定不是table definition cache的替代品,他的互斥锁(mutexes)和锁(locks)与LOCK_open互斥锁不同。 以下讨论提供了有关元数据锁定如何工作的一些信息。
  • 获得元数据锁
  • 释放元数据锁

获得元数据锁

如果对于一个给定的锁有很多的等待者,首先会满足权重最高的锁请求,并且和max_write_lock_count有关。写锁请求的权重高于读锁请求。 但是,如果将max_write_lock_count设置为某个较低的值(例如,10),则如果已经传递了读取锁定请求以支持10个写入锁定请求,则读取锁定请求可能优先于挂起的写入锁定请求。 通常不会发生此行为,因为默认情况下max_write_lock_count具有非常大的值。笔者废话:也就说读锁要让着写锁。这在数据库内部随处可见。写不能被饿死在文件系统也可体现呢。
语句逐个获取元数据锁,而不是同时获取,并在此过程中执行死锁检测。

DML语句获得锁的顺序和语句中提及到的表顺序一致。

DDL语句,LOCK TABLES和其他类似语句尝试通过按名称顺序获取显式命名表上的锁来减少并发DDL语句之间可能出现的死锁数。 对于隐式使用的表,可能以不同的顺序获取锁,比如外键关系的表也会被锁。笔者废话:一定要注意其中的名称顺序,实际上就是名称字典序。并非SQL语句中提及到的顺序。

比如说 RENAME TABLE 是一个DDL语句,它会根据顺序来获取锁。a c d
RENAME TABLE tbla TO tbld, tblc TO tbla;
如下获得锁顺序: a b c
RENAME TABLE tbla TO tblb, tblc TO tbla;
两个语句按顺序获取tbla和tblc上的锁,但是在tblc之前或之后是否获取,对剩余表名的锁定不同。(笔者废话:这就是废话吧)
当多个事务同时执行时,元数据锁获取顺序可以在操作结果上产生差异,如下例所示。
从两个具有相同结构的表x和x_new开始。 三个客户端发出涉及这些表的语句:
session1 LOCK TABLE x WRITE, x_new WRITE;
这个语句按x 、x_new 请求并获得锁。
session2 INSERT INTO x VALUES(1);
这个会话会被堵塞,因为它在等待x 的 写锁。
session3 RENAME TABLE x TO x_old, x_new TO x;
这个语句请求获得排他锁(exclusive lock),顺序是 x, x_new, x_old 。但是因为要获取x 写锁而被堵塞
session1 UNLOCK TABLES;
释放x 、x_new 的写锁,此时 session3 的排它锁(exclusive lock)请求比session2 的write lock有更高的优先级。索引执行顺序是先执行session3,然后才是session2的。(笔者注:这里的session3是要对metadata进行更改,所以需要的是一个排他锁,而session2对x表进行插入,并不涉及更改x的metadata,所以只是一个读锁,读锁是可以被其他读锁共享,也就是说不会影响其他插入。至于文档为什么写时write lock。不得而知。由于上述session2 ,session3 的两个操作都是瞬时完成,不好判断谁先谁后,读者可以根据binlog生成的顺序来验证。其实在官方的这个案例中,自带了有趣的验证,因为由于是先改名后插入,所以新插入的数据,实际上是在改名后的表中。)
mysql> SELECT * FROM x; 
+------+ | i    | 
+------+ |    1 | +------+ 
mysql> SELECT * FROM x_old; 
Empty set (0.01 sec)
以上证明了写锁高于读锁的请求
=================
现在来看以下案例。与上一同证明了DDL语句获取锁的顺序是字典序的
x 和 new_x 有相同的结构。再一次重复上述语句。
session1 LOCK TABLE x WRITE, new_x WRITE;
session2 INSERT INTO x VALUES(1); 
session3 RENAME TABLE x TO old_x, new_x TO x; 
session1 UNLOCK TABLES;

这时候,猜猜这个数据插入到哪里了。session3获得锁的顺序是new_x, x, old_x。而session2需要x锁。所以session2先插入记录到x中,然后x改名为old_x 。记录是在old_x中。

元数据锁的释放

为确保事务串行化,MySQL不得允许一个会话在另一个会话中未完成的显式或隐式启动的事务中使用的表上,执行数据定义语言(DDL)语句。服务器通过获取事务中使用的表的元数据锁并延迟释放这些锁直到事务结束来实现此目的。 表上的元数据锁可防止更改表的结构。 这种锁定方法的含义是,在事务结束之前,其他会话不能在DDL语句中使用一个会话中的事务正在使用的表。(译者废话:也就说,不允许在对一张表做操作过程中,表的结构被其他线程改了。这是很显然需要保护的)

这个规则不仅仅适用于事务表,对非事务表同样适用。假设一个会话以一个事务表 t 和一个非事务表 启动事务。如下:

START TRANSACTION; SELECT * FROM t; SELECT * FROM nt;

该会话持有t、nt的元数据锁,直到事务结束。如果有其他线程尝试在这两个表上做一个DDL语句(exclusive lock)或者write lock操作。比如,下面的语句都会被堵塞

DROP TABLE t; ALTER TABLE t ...; DROP TABLE nt; ALTER TABLE nt ...; LOCK TABLE t ... WRITE;
同样的行为适用于LOCK TABLES ... READ。 也就是说,更新任何表(事务性或非事务性)的显式或隐式启动事务将被阻塞。

如果服务获取语法有效但在执行期间失败的语句的元数据锁,则它不会提前释放锁(“译者注:比如插入冲突”)。 锁定释放仍然延迟到事务结束,因为失败的语句被写入二进制日志,并且锁定保护日志一致性。

在autocommit = true 的情况下,语句执行完,元数据锁就释放了。

在prepare语句后,即使在多语句事务中进行prepare,也会释放PREPARE语句期间获取的元数据锁。

MySQL metalock的一些技巧(写大于读的案例,以及获得锁的顺序)的更多相关文章

  1. 线上MySQL读写分离,出现写完读不到问题如何解决

    大家好,我是历小冰. 今天我们来详细了解一下主从同步延迟时读写分离发生写后读不到的问题,依次讲解问题出现的原因,解决策略以及 Sharding-jdbc.MyCat 和 MaxScale 等开源数据库 ...

  2. phpexcel如何读和写大于26列的excel

    主要运用到PHPExcel_Cell类的两个方法 1读取excel大于26列时. PHPExcel_Cell::columnIndexFromString($highestColumm)://由列名转 ...

  3. 【mysql注入】mysql注入点的技巧整合利用

    [mysql注入]mysql注入点的技巧整合利用 本文转自:i春秋社区 前言: 渗透测试所遇的情况瞬息万变,以不变应万变无谓是经验与技巧的整合 简介: 如下 mysql注入点如果权限较高的话,再知道w ...

  4. MySql 缓冲池(buffer pool) 和 写缓存(change buffer) 转

    应用系统分层架构,为了加速数据访问,会把最常访问的数据,放在缓存(cache)里,避免每次都去访问数据库. 操作系统,会有缓冲池(buffer pool)机制,避免每次访问磁盘,以加速数据的访问. M ...

  5. MySQL数据库调优技巧

    原文链接:https://m.aliyun.com/bbs/read/300762.html MySQL是一个功能强大的开源数据库.随着越来越多的数据库驱动的应用程序,人们一直在推动MySQL发展到它 ...

  6. MySQL优化十大技巧

    转自:https://m.2cto.com/database/201701/557910.html MYSQL优化主要分为以下四大方面: 设计:存储引擎,字段类型,范式与逆范式 功能:索引,缓存,分区 ...

  7. mysql幻读、MVCC、间隙锁、意向锁(IX\IS)

    IO即性能 顺序主键写性能很高,由于B+树的结构,主键如果是顺序的,则磁盘页的数据会按顺序填充,减少数据移动,随机主键则可能由于记录移动产生很多io 查询二级索引时,会再根据主键id获取数据页,产生一 ...

  8. 如何基于LSM-tree架构实现一写多读

    一  前言 PolarDB是阿里巴巴自研的新一代云原生关系型数据库,在存储计算分离架构下,利用了软硬件结合的优势,为用户提供具备极致弹性.海量存储.高性能.低成本的数据库服务.X-Engine是阿里巴 ...

  9. C#向文件写、读数据

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.T ...

随机推荐

  1. 初步STL该容器适配器

    容器适配器 特点 容器一定的顺序来实现(让现有的以集装箱堆放/式工作) 分类 1) stack: 头文件 <stack> • 栈 -- 后进先出 2) queue: 头文件 <que ...

  2. fzu-1753 Another Easy Problem-高速求N!多少个月p

    它计算每个C(N,M)什么号码乘以像.... #include <iostream> #include<stdio.h> #include<vector> #inc ...

  3. Windows静态库和动态库的创建和使用(VS2005)

    偶们在实际的编程开发中,经常会遇到运行时无法找到某个DLL文件或者链接时无法找到某个LIB文件.然后,我们就开始乱GOOGLE一下,然后将VS2005的设置改变一下,或许就Ok了,我们将别人开发的DL ...

  4. SICP 1.6-1.8

    1.6由于scheme应用序求值的性质,该函数会陷入循环(一直计算 improve guess x) 1.7 值过小,0.001这个精度远远不够... 值过大,由于浮点数精度有限,(比如使用IEEE7 ...

  5. Motion Paths in WPF 4 using Expression Blend 4

    原文 Motion Paths in WPF 4 using Expression Blend 4 Posted by: Pravinkumar Dabade , on 3/19/2011, in C ...

  6. 自动启动 Windows 10 UWP 应用

    原文: https://docs.microsoft.com/zh-cn/windows/uwp/xbox-apps/automate-launching-uwp-apps 简介 开发人员有多种选项可 ...

  7. Android adb socket 连接失败的问题

    pc客户端通过adb forward tcp 与android app通信 场景:pc启动,能正常建立连接,当断开连接再次连接,偶现pc客户端无法与forward 的端口建立 socket连接,连接请 ...

  8. /\B(?=(?:\d{3})+$)/g 一条令人费解的正则表达式

    网上浏览博客看到要用JavaScript正则表达式解决一个功能, 要在数字中间插入逗号, 用来表示书面的金额写法. JS代码是这样子的 let test1 = '1234567890' let for ...

  9. Elevate Web Builder for Web Developers(类似于unigui的东西)

    推荐一款pascal 语言的web 开发工具 这几天仔细研究了一款使用Pascal 语言开发web 的工具 具体介绍可以参照这里. 先上几张他开发的页面照.

  10. 使用WebBrowser并调用网页中的JS函数

    在界面上拖入QAxWidget,注意这里不建议直接在UI设计界面指定控件,否则可能引起QtCreator崩溃 建议在代码中动态设置,如: ui->axWidget->setControl( ...