2021-07-14

丁奇第8讲笔记

都是按照丁奇的45讲,自己看的过程总结下 方便复习
1、Mysql全局锁:MySQL里面的锁大致可以分成全局锁、表级锁和行锁三类,
MySQL提供了一个加全局读锁的方法,Flush tables with read lock (FTWRL)。当你需要让整个库处于只读状态的时候,可以使用这个命令,之后其他线程的以下语句会被阻塞:数据更新语句(数据的增删改)、数据定义语句(包括建表、修改表结构等)和更新类事务的提交语句。

全局锁的典型使用场景是,做全库逻辑备份。也就是把整库每个表都select出来存成文本。
注意问题:
如果你在主库上备份,那么在备份期间都不能执行更新,业务基本上就得停摆;
如果你在从库上备份,那么备份期间从库不能执行主库同步过来的binlog,会导致主从延迟。
备份不加锁:
不加锁的话,备份系统的备份得到的库不是一个逻辑时间点,这个视图是逻辑不一致的。
不使用readonly的原因:
1、在有些系统中,readonly的值会被用来做其他逻辑,比如用来判断一个库是主库还是备库。因此,修改global变量的方式影响面更大。
2、在异常处理机制上有差异。如果执行FTWRL命令之后由于客户端发生异常断开,那么MySQL会自动释放这个全局锁,整个库回到可以正常更新的状态。而将整个库设置为readonly之后,如果客户端发生异常,则数据库就会一直保持readonly状态,这样会导致整个库长时间处于不可写状态,风险较高。

即使没有被全局锁住,加字段也不是就能一帆风顺的,因为你还会碰到接下来我们要介绍的表级锁。
MySQL里面表级别的锁有两种:一种是表锁,一种是元数据锁(meta data lock,MDL)。
如何安全地给小表加字段?:
1、首先我们要解决长事务,事务不提交,就会一直占着MDL锁。在MySQL的information_schema 库的 innodb_trx 表中,你可以查到当前执行中的事务。如果你要做DDL变更的表刚好有长事务在执行,要考虑先暂停DDL,或者kill掉这个长事务。
2、ALTER TABLE tbl_name NOWAIT add column …
比较理想的机制是,在alter table语句里面设定等待时间,如果在这个指定的等待时间里面能够拿到MDL写锁最好,拿不到也不要阻塞后面的业务语句,先放弃。之后开发人员或者DBA再通过重试命令重复这个过程。

互斥性:
(1)读锁之间不互斥,因此你可以有多个线程同时对一张表增删改查(这相当于行操作)。
(2)读写锁之间、写锁之间是互斥的,用来保证变更表结构操作的安全性。因此,如果有两个线程要同时给一个表加字段,其中一个要等另一个执行完才能开始执行。
(在这里要注意:(1)中是对于表来说的,加了mdl或者表锁,给表上读锁 不影响对表内行字段的增删改查,)

这里插入一个MySQL备份原理:
https://blog.csdn.net/qq_34556414/article/details/106781973
备份的方式:
(1):冷备份:关掉数据库 复制文件
(2):热备份:不关闭直接备份
都是热备份:
(1):逻辑备份:大多用mysqldump工具 备份的是sql语句
(2):快照备份:通过快照备份,linux系统中,LVM使用写时复制(copy-on-write)技术来创建快照。使用预存区来保存
主要是mysqldump进行逻辑备份
原理:

--single-transcation
--master-data=2
 
--master-data=2--master-data=1 默认的话会--lock-all-tables,会锁住整个mysql数据库中的所有表。但是如果加上--single-transaction会加上事务,不会锁表

1 、对于支持事务的引擎如 InnoDB , 参数上是在备份的时候加上 –single-transaction 保证数据一致性

–single-transaction 实际上通过做了下面两个操作 :

① 在开始的时候把该 session 的事务隔离级别设置成 repeatable read (可重复读);

② 然后启动一个事务(执行 begin ),备份结束的时候结束该事务(执行 commit )

有了这两个操作,在备份过程中,该 session 读到的数据都是启动备份时的数据(同一个点)。可以理解为对于 innodb 引擎来说加了该参数,备份开始时就已经把要备份的数据定下来了,备份过程中的提交的事务时是看不到的,也不会备份进去。

08讲事务到底是隔离的还是不隔离的总结:
1、可重复度是怎么做到的:是看读语句的读示图read-view是在什么时间启动的,
立刻启动一个事务语句:start transaction with consistent snapshot
2、在MySQL里,有两个“视图”的概念:作用是事务执行期间用来定义“我能看到什么数据”。
一个是view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是create view … ,而它的查询方法与表一样。
另一个是InnoDB在实现MVCC时用到的一致性读视图,即consistent read view,用于支持RC(Read Committed,读提交)和RR(Repeatable Read,可重复读)隔离级别的实现。
真实的视图不可见原因是看视图id
在这里插入图片描述如果落在绿色部分,表示这个版本是已提交的事务或者是当前事务自己生成的,这个数据是可见的;

如果落在红色部分,表示这个版本是由将来启动的事务生成的,是肯定不可见的;

如果落在黄色部分,那就包括两种情况
a. 若 row trx_id在数组中,表示这个版本是由还没提交的事务生成的,不可见;
b. 若 row trx_id不在数组中,表示这个版本是已经提交了的事务生成的,可见。
实际判断的时候 我们肯定不能画视图,遵循下面三种判断原则:
1、版本未提交,不可见;
2、版本已提交,但是是在视图创建后提交的,不可见;
3、版本已提交,而且是在视图创建前提交的,可见。
例:在这里插入图片描述在这个图片中事务A查到的是1,事务B查到的是3
解释:用视图id解释,这三个事务开启前的版本是99,
事务A的当前版本号是:[100] 指向99 ,整体链路【99->100】
事务B的当前版本号是:101 指向100 ,整体链路【99->100->101】
事务C的当前版本号是:102指向101,整体链路 【99->100->101->102】
90 是历史版本 102是上一版本 101是当前版本
在这里插入图片描述
当B去查询时 当前版本是101 B可见的是3
A去查询时 只能对90那个版本可见 所以看见的是1
而事务B更新数据是开启了当前读,当前读会去取当前最新数据,在最新数据上操作,更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)事务B在更新的时候,当前读拿到的数据是(1,2),更新后生成了新版本的数据(1,3),这个新版本的row trx_id是101。除了update语句外,select语句如果加锁,也是当前读。
所以,如果把事务A的查询语句select * from t where id=1修改一下,加上lock in share mode 或 for update,也都可以读到版本号是101的数据,返回的k的值是3。下面这两个select语句,就是分别加了读锁(S锁,共享锁)和写锁(X锁,排他锁)。
mysql> select k from t where id=1 lock in share mode;
mysql> select k from t where id=1 for update;
如果 ,事务B在update之前 C更改了但是没提交,此时B的update是被阻塞的,C释放锁之后B才能进行当前读

  • 在可重复读隔离级别下,只需要在事务开始的时候创建一致性视图,之后事务里的其他查询都共用这个一致性视图;
  • 在读提交隔离级别下,每一个语句执行前都会重新算出一个新的视图。
  • 对于可重复读,查询只承认在事务启动前就已经提交完成的数据;
  • 对于读提交,查询只承认在语句启动前就已经提交完成的数据;
    PS:虽然根据事务id看是否可见,但是如果找到了一个事务id比当前的小,但这个小的id在正在执行的所有事物ID列表中, 也要不可见,即事务id虽然启动早, 但是我没执行完
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值