MVCC
Mysql/Oracle等数据库 均实现了MVCC(多版本并发控制),但各自的实现机制不尽相同。
Mysql的事务性存储引擎才可以实现MVCC,可以认为MVCC是行级锁的一个变种,但是它在很多情况下避免了加锁操作。
MVCC的实现,是通过保存数据在某个时间点的快照来实现的
InnoDB的MVCC,是通过在每行记录后面保存两个隐藏的列来实现的。一个保存了行的创建时间,一个保存了行的过期时间
“快照”在MVCC中作用(此小节来自极客时间付费课程 欢迎购买对应课程)
在可重复读隔离级别下,事务在启动的时候就“拍了个快照”。注意,这个快照是基于整库的
InnoDB 里面每个事务有一个唯一的事务 ID,叫作 transaction id。它是在事务开始的时候向 InnoDB 的事务系统申请的,是按申请顺序严格递增的。而每行数据也都是有多个版本的。每次事务更新数据的时候,都会生成一个新的数据版本,并且把 transaction id 赋值给这个数据版本的事务 ID,记为 row trx_id。
同时,旧的数据版本要保留,并且在新的数据版本中,能够有信息可以直接拿到它。也就是说,数据表中的一行记录,其实可能有多个版本 (row),每个版本有自己的 row trx_id。
img视图
在 MySQL 里,有两个“视图”的概念:
-
一个是 view。它是一个用查询语句定义的虚拟表,在调用的时候执行查询语句并生成结果。创建视图的语法是 create view … ,而它的查询方法与表一样。
-
另一个是 InnoDB 在实现 MVCC 时用到的一致性读视图,即 consistent read view,用于支持 RC(Read Committed,读提交)和 RR(Repeatable Read,可重复读)隔离级别的实现。
这里视图,即是上文所说的快照
隔离级别
ACID(Atomicity、Consistency、Isolation、Durability,即原子性、一致性、隔离性、持久性),今天我们就来说说其中 I,也就是“隔离性”
当数据库上有多个事务同时执行的时候,就可能出现脏读(dirty read)、不可重复读(non-repeatable read)、幻读(phantom read)的问题,为了解决这些问题,就有了“隔离级别”的概念。
在谈隔离级别之前,你首先要知道,你隔离得越严实,效率就会越低。因此很多时候,我们都要在二者之间寻找一个平衡点。SQL 标准的事务隔离级别包括:读未提交(read uncommitted)、读提交(read committed)、可重复读(repeatable read)和串行化(serializable )。下面我逐一为你解释:
-
读未提交是指,一个事务还没提交时,它做的变更就能被别的事务看到。
-
读提交是指,一个事务提交之后,它做的变更才会被其他事务看到。
-
可重复读是指,一个事务执行过程中看到的数据,总是跟这个事务在启动时看到的数据是一致的。当然在可重复读隔离级别下,未提交变更对其他事务也是不可见的。
-
串行化,顾名思义是对于同一行记录,“写”会加“写锁”,“读”会加“读锁”。当出现读写锁冲突的时候,后访问的事务必须等前一个事务执行完成,才能继续执行。
数据库里面会创建一个视图,访问的时候以视图的逻辑结果为准。
-
在“可重复读”隔离级别下,这个视图是在事务启动时创建的,整个事务存在期间都用这个视图。
-
在“读提交”隔离级别下,这个视图是在每个 SQL 语句开始执行的时候创建的。这里需要注意的是,
-
“读未提交”隔离级别下直接返回记录上的最新值,没有视图概念;
-
而“串行化”隔离级别下直接用加锁的方式来避免并行访问。
事务的视图规则
对于一个事务来说,除了自己的更新总是能看到以外,其余的遵守以下规则
- 版本未提交,不可见
- 版本已提交,但是在视图创建后提交的,不可见
- 版本已提交,在视图创建前提交的,可见
另外:
- 更新数据都是先读后写的,而这个读,只能读当前的值,称为“当前读”(current read)
网友评论