什么是事务
简单来说事务就是一组数据库操作要么全部成功,要么全部失败。Mysql的事务实现是在引擎层实现的。MyISAM 引擎不支持事务。
事务的隔离级别
提到事务,一定绕不开ACID,即:原子性、一致性、隔离性、持久性。今天聊聊事务的隔离性。
为什么要有隔离性?换句话说,隔离性解决了什么问题?当数据库里有多个事务同时执行的时候,可能出现:脏读、不可重复读、幻读的问题,后面会详细介绍。为了解决这些问题,就有了隔离级别的概念。**
SQL标准的隔离级别包括
- 读未提交,指的是,一个事务还没提交,它的修改就能被别的事务看到。
- 读提交,指的是,一个事务提交后,它的修改才能被别的事务看到。
- 可重复读,指的是,一个事务执行过程中看到是数据,总是跟事务启动时看到的数据一致。
- 串行化,指的是,读加读锁,写加写锁。当出现读写冲突时,只有等前面事务执行完成,后面的事务才能继续执行。
举个例子:
创建一个表t,只有一个字段c,并插入一行记录:
mysql> create table t(c int) engine=InnoDB; insert into t(c) values(1);
我们来看看,在不同的隔离级别下,事务A查询的V1、V2、V3分别是多少:
- 读未提交,事务A可以看到事务B未提交的修改,所以:V1、V2、V3的值都是2;
- 读提交,事务B的修改在,提交后才能被事务A看到,所以V1=1,v2=v3=2;
- 可重复读,事务A看到的结果跟启动时看到的结果一致,v1=v2=1,之后事务A提交,在查询v3的时候,此时事务B的更新能看到,所以v3=2;
- 串行化,事务启动加读锁,之后因为读锁是共享的,所以事务B可以查询得到1,之后的修改操作,需要加写锁,读写锁互斥,所以修改等待,直到事务A提交释放读锁,事务B才能更新。所以,v1=v2=1,v3=2。
事务隔离级别的实现
理解了事务的隔离级别,我们再来看,事务的隔离级别是如何实现的,下面展开说明“可重复读”的实现。
在Mysql中,实际上每条记录在更新的时候都会在回滚日志(undo log)中记录一条回滚操作。记录的最新值加上回滚段,就可以得到前一个状态的值。
假设一个值从1被顺序更新为2、3、4,在回滚日志里就会有类似下面的记录
不同时刻启动的事务,有不同的视图,也就是说,一条记录在系统中可能有多个版本存在,这就是数据库的多版本并发控制(MVCC)。对于视图A来说,想要得到1,必须将当前值4,依次执行所有的回滚操作。
回滚日志的删除逻辑:系统判断当前系统里没有被这个回滚日志更早的视图的时候,就会删除该回滚日志。
尽量少使用长事务,因为长事务意味着系统里会存在很老的视图,为了保存这些回滚日志,浪费空间。长事务除了对回滚段的影响,也会占用锁资源,导致可能拖垮整个库。
事务控制语句
- START TRANSACTION | BEGIN // 显示开启事务
- COMMIT // 提交事务,并使得已对数据库做的所有修改持久化
- ROLLBACK // 回滚事务,结束用户的事务,并撤销正在进行的所有未提交的修改
笔记参考于极客时间《MySQL实战45讲》