文章目录
- 事务未提交和提交
- 事务的4大特征
- 事务的隔离级别
- 并发事务的问题
- MVVC
- undo log 和 redo log
- 记录的隐藏字段
- readview(读视图)
事务未提交和提交
事务未提交时数据存在于数据库系统的缓存中,而在事务提交后,数据才会被写入到磁盘上的数据库文件中。
事务的4大特征
事务的四大特征
原子性:事务不可分割,要么全部成功,要么全部失败
一致性:事务的一致性要求数据库在任何时候都保持一致的状态,不会出现数据的矛盾或不完整。(数据总额不能变)
隔离性:并发执行的事务之间互不干扰。
持久性:事务一旦提交, 其对数据库的修改是永久性的
事务的隔离级别
MySQL支持四种隔离级别,分别有:
读 未提交(read uncommitted)可以读到未提交的数据。会造成脏读,不可重复读和幻读。
读 已提交(read committed)只会读已提交的数据。它能解决脏读的问题的,但是解决不了不可重复读和幻读。
可重复 读(repeatable read)它确保同一事务的多个实例在并发读取数据时,会看到同样的数据行。它能解决脏读和不可重复读,但是解决不了幻读,这个也是mysql默认的隔离级别。
第四个是串行化(serializable)这是最高的隔离级别,它通过强制事务排序,使之不可能相互冲突,从而解决幻读问题。简言之,它是在每个读的数据行上加上共享锁。在这个级别,可能导致大量的超时现象和锁竞争。
编者按:事务顺序执行,没有并行,完全杜绝幻读。
并发事务的问题
面试官:并发事务带来哪些问题?
候选人:
脏读,读到其他事务还未提交的数据。
不可重复读:一个事物先后读取两次同一条记录。在第一次读取后,其他事务修改了该数据,导致第二次读到的数据和第一次不同。
幻读(Phantom read):
select的时候没有发现某条记录,插入的时候又发现记录已经存在,好像自己出现了幻觉一样。
幻读错误的理解
说幻读是 事务A 执行两次 select 操作得到不同的数据集,即 select 1 得到 10 条记录,select 2 得到 15 条记录。这其实并不是幻读,既然第一次和第二次读取的不一致,那不还是不可重复读吗,所以这是不可重复读的一种。
正确的理解
幻读,并不是说两次读取获取的结果集不同,幻读侧重的方面是某一次的 select 操作得到的结果所表征的数据状态无法支撑后续的业务操作。更为具体一些:select 某记录是否存在,不存在,准备插入此记录,但执行 insert 时发现此记录已存在,无法插入,此时就发生了幻读。
MVVC
面试官:事务中的隔离性是如何保证的呢?(你解释一下MVCC)
候选人:事务的隔离性是由锁和mvcc实现的。
mvcc(多版本并发控制)。指维护一个数据的多个版本,使得读写操作没有冲突,它的底层实现主要是分为了三个部分,第一个是隐藏字段,第二个是undo log日志,第三个是readView读视图
隐藏字段,在mysql中给每个表都设置了隐藏字段,有一个是trx_id(事务id),记录每一次操作的事务id,是自增的;另一个字段是roll_pointer(回滚指针),指向上一个版本的事务版本记录地址
undo log,主要的作用是记录回滚日志,存储老版本数据,在内部会形成一个版本链,在多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过roll_pointer指针形成一个链表
readView,解决的是一个事务查询选择版本的问题,在内部定义了一些匹配规则和当前的一些事务id判断该访问那个版本的数据,不同的隔离级别快照读是不一样的,最终的访问的结果不一样。如果是rc隔离级别,每一次执行快照读时生成ReadView,如果是rr隔离级别仅在事务中第一次执行快照读时生成ReadView,后续复用
undo log 和 redo log
Undo log(回滚日志) 记录了事务对数据所做的修改操作的逆操作,即撤销操作。当事务进行修改时,会先将修改前的数据记录到 undo log 中,以便在事务回滚或者发生异常时能够恢复到事务开始之前的状态。
保证事务的原子性和一致性。
redo log(重做日志)
Redo log 记录了事务对数据所做的修改操作,即重做操作。当事务对数据库进行修改时,将相应的修改操作记录到 redo log 中,确保这些操作能够在系统崩溃后被重放以保证事务的持久性。
保证事务的持久性
记录的隐藏字段
不同事务或相同事务对同一条记录进行修改,会导致该记录的undolog生成一条记录版本链表,链表的头部是最新的旧记录,链表尾部是最早的旧记录。
事务id,回滚指针(指向undo log中的记录的上一个版本),隐藏主键
示例:
事务2执行
事务3执行
事务4执行