丁奇mysql实战45讲(三)笔记

[3. 事务隔离:为什么你改了我还看不见?]

基本概念复习:

事务的特性:原子性、一致性、隔离性、持久性

多事务同时执行的时候,可能会出现的问题:脏读、不可重复读、幻读

事务隔离级别:读未提交、读提交、可重复读、串行化

img img img

一.Mysql的隔离级别

1.读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。(可以读到其他事务未提交的数)

2.读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。(事务提交了才能读到数)

3.可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。(事务A读到的值和刚进入事务时读到的值一样,不受其他事务干扰)

4.串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。

举例:

mysql> create table T(c int) engine=InnoDB;

 insert into T(c) values(1);

下面事务A和事务B要读取1的值并进行操作,操作如下图

img

①若隔离级别是“读未提交”, 则 V1 的值就是 2。这时候事务 B 虽然还没有提交,但是结果已经被 A 看到了。因此,V2、V3 也都是 2。

②若隔离级别是“读提交”,则 V1 是 1,V2 的值是 2。事务 B 的更新在提交后才能被 A 看到。所以, V3 的值也是 2。

③若隔离级别是“可重复读”,则 V1、V2 是 1,V3 是 2。之所以 V2 还是 1,遵循的就是这个要求:事务在执行期间看到的数据前后必须是一致的。

④若隔离级别是“串行化”,则在事务 B 执行“将 1 改成 2”的时候,会被锁住。直到事务 A 提交后,事务 B 才可以继续执行。所以从 A 的角度看, V1、V2 值是 1,V3 的值是 2。

注:这里注意一下读提交和可重复读的区别,都提交是B事务提交了就会影响到A,可重复读是A开启事务后读的值B事务完全无法影响

二.隔离级别的实现原理以及

在实现上,数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。

①"读未提交"没有视图概念,直接返回记录上的最新值

②“读提交”的视图是在每个SQL语句开始执行的时候创建的

③“可重复读”这个视图是在事务启动时创建的,整个事务存在期间都用这个视图

④"串行化"没有视图概念,因为已经用锁来避免并行访问了

为保证数据库隔离级别的一致,你一定要记得将 MySQL 的隔离级别设置为“读提交”。配置的方式是,将启动参数 tx_isolation 的值设置成 READ-COMMITTED。你可以用 show variables 来查看当前的值。

SHOW VARIABLES LIKE 'tx_isolation';//查看事务的隔离级别 

SET  tx_isolation='READ-COMMITTED'//修改事务的隔离级别 

//读未提交:READ-UNCOMMITTED 

//读提交:READ-COMMITTED 

//可重复读:REPEATABLE-READ 

//串行化:SERIALIZABLE

事务隔离的实现以及长事务的问题:

①原理:在 MySQL 中,实际上每条记录在更新的时候都会同时记录一条回滚操作。记录上的最新值,通过回滚操作,都可以得到前一个状态的值。不同时刻启动的事务会有不同的 read-view(读视图)。而对于这些回滚日志,系统会在做出判断,当没有事务再需要用到这些回滚日志时,回滚日志会被删除。

判断标准:当没有比回滚日志更早的读视图(读视图在事务开启时创建)的时候,这个数据不会再有谁驱使它回滚了,这个回滚日志也就失去了用武之地,可以删除了

②要避免长事务:基于上面的原理,自然会想到一个问题,如果事务内容过长,那么回滚日志必然会占用大量的空间。最终只能清理回滚段,重建整个库。除了对回滚段的影响,长事务还占用锁资源,也可能拖垮整个库。所以日常开发中尽量别用长事务。

③在开发过程中,尽可能的减小事务范围,少用长事务,如果无法避免,保证逻辑日志空间足够用,并且支持动态日志空间增长。监控Innodb_trx表,发现长事务报警。

三.事务的启动方式

①如果set autocommit=0,那么默认就是要手动commit,这时即使只执行了一条select语句也等于开启了事务,长此以往,如果是长连接,就导致了意外的长事务。所以建议手动开启使用set autocommit=1

②过显式语句的方式来启动事务。但是对于一个需要频繁使用事务的业务,可以使用commit work and chain来代替commit,因为这条语句可以在执行完一个事务的时候自动开启下一个事务,就可以省去再次执行begin语句的开销

③你可以在 information_schema 库的 innodb_trx 这个表中查询长事务,比如下面这个语句,用于查找持续时间超过 60s 的事务。

select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值