作为一个后端工程师,想必没有人没用过数据库,跟我一起复习一下MySQL吧,本文是我学习《MySQL实战45讲》的总结笔记的第二篇,总结了MySQL的事务隔离级别。
上一篇:MySQL核心知识学习之路(1)
1 MySQL的事务隔离级别
所谓隔离,它源自于我们熟知的事务的ACID四大特性之一的Isolation隔离性。
如果事务之间不隔离,那么可能会发生以下几个问题:
(1)脏读
脏读指的是读到了其他事务未提交的数据,而这些数据可能会被回滚。
(2)不可重复读
不可重复读值的是在同一事务内,不同时刻读到的同一批数据可能是不一样的,可能会受到其他事务的影响,比如其他事务改了这批数据并提交了。通常针对UPDATE操作。
(3)幻读
幻读指的是一个事务在进行一次查询之后发现某个记录不存在,然后会根据这个结果进行下一步操作,此时如果另一个事务成功插入了该记录,那么对于第一个事务而言,其进行下一步操作(比如插入该记录)的时候很可能会报错。通常针对INSERT操作。
为了解决这些问题,在MySQL中,提供了如下四种事务的隔离级别:
在MySQL中,提供了如下四种事务的隔离级别:
- 读未提交(Read Uncommitted)
- 一个事务还未提交,它所做的变更就可以被别的事务看到
- 读提交(Read Committed)
- 一个事务提交之后,它所做的变更才可以被别的事务看到
- 可重复读(Repeatable Read):默认隔离级别
- 一个事务执行过程中看到的数据是一致的。未提交的更改对其他事务是不可见的
- 串行化(Searializable)
- 对应一个记录会加读写锁,出现冲突的时候,后访问的事务必须等前一个事务执行完成才能继续执行
如上四种隔离级别,并行性能依次降低,安全性则依次提高!
在MySQL中,可以通过以下命令查看当前设置的事务隔离级别,默认隔离级别为可重复读(Repeatable Read)
代码语言:javascript复制mysql> show variables like 'transaction_isolation';
如果要修改默认隔离级别为读提交:(以下为修改全局事务隔离级别)
代码语言:javascript复制mysql> set global transaction isolation level read committed;
事务隔离是为了解决脏读、不可重复读、幻读这几个问题,下图展示了这四种隔离级别对这三个问题的解决程度:
可以看到,只有串行化的隔离级别解决了全部问题,其他的隔离级别都各有缺陷。不过,串行化虽然可以解决所有问题,但是并发性能最差。
2 隔离级别小练习
现在我们来看一个小练习,假设我们通过以下语句创建一张表T,并向表T插入了一个新数值1:
代码语言:javascript复制mysql> create table T(c int) engine=InnoDB;insert into T(c) values(1);
然后,看看如下所示的图片,假设有两个事务分别启动,看看在不同的隔离级别下不同事务查询得到的值V1、V2和V3分别是多少?
图片来源:林晓斌《MySQL实战45讲》
(1)隔离级别=读未提交,V1=V2=V3=2
(2)隔离级别=读提交,V1=1,V2=V3=2
(3)隔离级别=可重复读,V1=V2=1,V3=2
(4)隔离级别=串行化,V1=V2=1,V3=2
3 事务隔离的实现
在MySQL中,每条记录在更新的时候都会同时记录一条回滚操作。因此,记录上的最新的值,通过回滚操作,可以得到前一个状态的值。换句话说,同一条记录在系统中可以存在多个版本,这其实就是MySQL数据库的多版本并发控制(MVCC)。
综述,可以说MySQL事务隔离的实现基础是基于多版本并发控制MVCC的,而具体的实现方式就是回滚日志。即每个事务的都会在自己的一致性读视图(Consistent Read View,这个视图没有物理结构,用来在事务执行期间定义“我能看到什么数据”)中对记录进行操作,并记录回滚日志,但是不同事务之间是不会冲突的。
鉴于此,由于长事务会存在很老的事务视图,在其未提交之前,可能用到的所有回滚记录都需要保留,会占用大量存储空间。所以,建议尽量不要使用长事务!
如果必须要用,那么需要对其进行监控,下面的语句可以指导我们查找时间超过60s的长事务:
代码语言:javascript复制-- 查找持续时间超过60s的长事务
select * from information_schema.innodb_trx where TIME_TO_SEC(timediff(now(),trx_started))>60
4 事务的启动方式
在实践中,MySQL的事务启动方式有以下两种:
(1)显示启动事务(begin/start transaction -> commit/rollback)
(2)显示关闭自动提交(set autocommit=0)
5 小结
本文总结了MySQL的事务隔离级别、实现方式 及 启动方式,可以帮助我们使用好MySQL的事务特性。
参考资料
林晓斌(丁奇),《MySQL实战45讲》