前言

锁从大的方面可以分为:

1.全局锁

2.表锁

3.行锁

正文

全局锁

全局锁就是对整个数据加上读锁。

在mysql 中,加入全局锁的命令就是: Flush tables with read lock(FTWRL)

这个时候会让整个数据库处于只读状态,之后其他线程的数据更新、数据定义语句和更新类事务提交语句将会被堵塞。

那么有一个问题了,为什么不设置set global readonly=true。

一是,在有些系统中,readonly的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改global变量的方式影响面更大,我不建议你使用。

二是,在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。

而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。

业务的更新不只是增删改数据(DML),还有可能是加字段等修改表结构的操作(DDL)。

不论是哪种方法,一个库被全局锁上以后,你要对里面任何一个表做加字段操作,都是会被锁住的。

但是,即使没有被全局锁住,加字段也不是就能一帆风顺的,因为你还会碰到接下来我们要介绍的表级锁。

全局锁的典型使用场景是,做全库逻辑备份。

为什么做全库的备份要加全局锁?又为什么建议从库备份呢?

先介绍为什么要在从库进行备份,在从库进行备份就很简单了。

1.如果在主库备份,那么在备份期间都不能执行更新,业务基本停止了。

2.在从库备份,主从会导致延迟。

这其他都不好的,第二个好点,但是呢,会出现比如用户更新了,但是人家一查询,发现没有更新,这就要打客服了。

那么有没有更好的办法呢? 可以使用热备库,有一台机器一般专门用来做热备的服务器,这样备份的时候就在热备服务器,这样就不影响线上了。

那么为什么备份的时候要加全局锁呢?

比如说,用户购买业务,里面有一张用户表,用户表里面有一个金额字段。同样,还有一张购买的商品表,如果用户购买了商品将会在这里面。

业务逻辑是先扣除用户的金额,然后再给用户加入一个商品。

为什么是先扣除金额呢?因为是这样的,我们一般会写成事务,但是呢,如果系统发送不可挽回的崩溃了,用户金额少了,商品不见了,那么用户会报告。如果是商品在,金额没少,那么这个时候是没人会报告的。

加入现在不锁表,那么出现这样的情况。

现在如果先备份用户表,这个时候是在用户表备份完了之后,然后用户开始购买成功,并且商品表里面加入了该数据,这个时候呢,备份商品表,然后你就发现一个问题,备份里面用户金额没有扣除,然后商品表多了商品。

反过来先备份商品,然后备份用户,结果就是反过来的了。

那么问题来了是不是一定要有一个热备的服务器(或者数据库)才能不影响线上用户啊?

在可重复读隔离级别下开启一个事务。

官方自带的逻辑备份工具是mysqldump。当mysqldump使用参数–single-transaction的时候,导数据之前就会启动一个事务,来确保拿到一致性视图。而由于MVCC的支持,这个过程中数据是可以正常更新的。

故而,需要在整个库的每个表示在可重复读隔离级别的情况下。

表锁

MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。

表锁的语法是 lock tables …read/write。与FTWRL类似,可以用unlock tables主动释放锁,

也可以在客户端断开的时候自动释放。需要注意,lock tables语法除了会限制别的线程的读写外,也限定了本线程接下来的操作对象。

举个例子, 如果在某个线程A中执行lock tables t1 read, t2 write; 这个语句,则其他线程写t1、读写t2的语句都会被阻塞。

同时,线程A在执行unlock tables之前,也只能执行读t1、读写t2的操作。连写t1都不允许,自然也不能访问其他表。

另一类表级的锁是MDL(metadata lock)。MDL不需要显式使用,在访问一个表的时候会被自动加上。

MDL的作用是,保证读写的正确性。你可以想象一下,如果一个查询正在遍历一个表中的数据,而执行期间另一个线程对这个表结构做变更,删了一列,那么查询线程拿到的结果跟表结构对不上,肯定是不行的。

因此,在MySQL 5.5版本中引入了MDL,当对一个表做增删改查操作的时候,加MDL读锁;当要对表做结构变更操作的时候,加MDL写锁。

读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查。

读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。

虽然MDL锁是系统默认会加的,但是MDL也有一个大坑。

可以看到session A先启动,这时候会对表t加一个MDL读锁。由于session B需要的也是MDL读锁,因此可以正常执行。

之后session C会被blocked,是因为session A的MDL读锁还没有释放,而session C需要MDL写锁,因此只能被阻塞。

如果只有session C自己被阻塞还没什么关系,但是之后所有要在表t上新申请MDL读锁的请求也会被session C阻塞。

前面我们说了,所有对表的增删改查操作都需要先申请MDL读锁,就都被锁住,等于这个表现在完全不可读写了。

如果某个表上的查询语句频繁,而且客户端有重试机制,也就是说超时后会再起一个新session再请求的话,这个库的线程很快就会爆满。

如果是短事务,大表依然可能出现这种情况。因为增加一个字段,时间比较长,那么可能其他语句肯定都被锁住了。

那么该怎么办呢?

在上面中,造成这个的原因是因为session A 是长事务,一直占用MDL锁。

如果发现这种情况,可以先杀死这个事务,也就是杀死这个会话。

然后如果发现sessionA 这种事务比较频繁,那么可能还是不适用。除此之外,如果表大的话,增加一个字段耗费时间比较长的话,依然会有问题。

那么可以设置另外一个东西,那就是MDL写锁限定时间,如下:

MariaDB 中可以使用:

ALTER TABLE tbl_name NOWAIT add column ...
ALTER TABLE tbl_name WAIT N add column ...

下一节,行锁。

重新整理 mysql 基础篇—————表锁和全局锁[六]的更多相关文章

  1. 重新整理 mysql 基础篇————— 介绍mysql[一]

    前言 准备整理mysql的基础篇了,前面整理了sql语句序列的的<sql 语句系列(八百章)>,感觉很多用不上,就停下来了,后续还是会继续整理. mysql 基础篇主要是对一些基础进行整理 ...

  2. 重新整理 mysql 基础篇————— mysql 事务[三]

    前言 简单整理一下事务. 正文 事务有四大特性: 1.原子性(atomicity) 一个事务必须被视为一个不可分割的最小单元. 2.一致性(consistency) 数据库总是从一个一致性的状态转换到 ...

  3. 重新整理 mysql 基础篇————— 介绍mysql日志[二]

    前言 对于后端开发来说,打交道最多的应该是数据库了,因为你总得把东西存起来. 或是mongodb或者redis又或是mysql.然后你发现一个问题,就是他们都有日志系统,那么这些日志用来干什么的呢? ...

  4. 重新整理 mysql 基础篇————— 事务隔离级别[四]

    前言 简单介绍一下事务隔离的基本 正文 Read Uncommitted(未提交读) 这个就是读未提交.就是说在事务未提交的时候,其他事务也可以读取到未提交的数据. 这里举一个例子,还是前一篇的例子. ...

  5. mysql基础篇--表的管理

    表的创建 常见的数据类型 数值型: 整型 tinyint.smallint.mediumint.int/integer.bigint 特点: 1.如果不设置无符号还是有符号,默认是有符号,如果想设置无 ...

  6. 【目录】mysql 基础篇系列

    随笔分类 - mysql 基础篇系列 mysql 开发基础系列22 SQL Model(带迁移事项) 摘要: 一.概述 与其它数据库不同,mysql 可以运行不同的sql model 下, sql m ...

  7. Mysql实战45讲 06讲全局锁和表锁:给表加个字段怎么有这么多阻碍 极客时间 读书笔记

    Mysql实战45讲 极客时间 读书笔记 Mysql实战45讲 极客时间 读书笔记 笔记体会: 根据加锁范围:MySQL里面的锁可以分为:全局锁.表级锁.行级锁 一.全局锁:对整个数据库实例加锁.My ...

  8. synchronized是对象锁还是全局锁

    昆昆欧粑粑 2019-02-20 15:09:59 1148 收藏 1分类专栏: java学习 文章标签: synchronized 全局锁 对象锁 同步版权都可以锁!synchronized(thi ...

  9. mysql基础篇 - 数据库及表的修改和删除

    基础篇 - 数据库及表的修改和删除         修改和删除 一.实验简介 本节实验中,我们将学习并实践如何对数据库的内容做修改,删除,重命名等操作. 二.实验准备 在正式开始本实验内容之前,需要先 ...

  10. MySQL基础篇(06):事务管理,锁机制案例详解

    本文源码:GitHub·点这里 || GitEE·点这里 一.锁概念简介 1.基础描述 锁机制核心功能是用来协调多个会话中多线程并发访问相同资源时,资源的占用问题.锁机制是一个非常大的模块,贯彻MyS ...

随机推荐

  1. Java 多线程------例子(2) --创建 三个窗口 买票 总票数为 100张 使用实现Runnabel接口的方式

    1 package com.bytezero.threadexer; 2 3 /** 4 * 创建 三个窗口 买票 总票数为 100张 使用实现Runnabel接口的方式 5 * 6 * @autho ...

  2. Alertmanager钉钉告警

    一.部署alertmanager 1.1 创建目录 mkdir -p /deploy/app/alertmanager/config chmod -R 777 /deploy/app/alertman ...

  3. vue3,实战项目随心笔记

    本项目模仿bibi 网站,主要是做一个pc和手机端的应用案例,主要涉及支付,三方登陆,css原子,妹子ui,路由缓存,组件封装,tailwindcss,vueuse 等常见企业级术应用, 由于本项目是 ...

  4. Python面向对象之派生和组合

    [一]什么是派生 派生是指,子类继承父类,派生出自己的属性与方法,并且重用父类的属性与方法 [二]派生的方法 子类可以派生出自己新的属性,在进行属性查找时,子类中的属性名会优先于父类被查找 例如每个老 ...

  5. Github无法读取远程仓库

    主页 个人微信公众号:密码应用技术实战 个人博客园首页:https://www.cnblogs.com/informatics/ Git无法访问 今早起来访问Github炸了,Git不能用了,提示: ...

  6. ansible 自动化运维(2)

    回到顶部 Ansible playbook 简介 playbook 是 ansible 用于配置,部署,和管理被控节点的剧本. 通过 playbook 的详细描述,执行其中的一系列 tasks ,可以 ...

  7. netcore 图片缩略图

    /// <summary> /// 取小写文件名后缀 /// </summary> /// <param name="name">文件名< ...

  8. rancher添加用户报错x509: certificate has expired Internal error occurred: failed calling webhook "rancherauth.cattle.io":

    错误信息: Internal error occurred: failed calling webhook "rancherauth.cattle.io": Post https: ...

  9. [【stars-one】Android图标生成器 PC工具

    原文: [stars-one]Android图标生成器 - Stars-One的杂货小窝 一款Android开发者的PC工具软件,可以快速生成android开发需要使用的xml矢量图标文件 起因 个人 ...

  10. webserver总结

    可设置参数:连接池最大连接数,最大线程数,任务队列最大值,timeslot epoll epoll监听listen_fd(接受新客户端和断开连接), pipefd(将信号输入到管道用epoll统一管理 ...