一、事物的特性
原子性:通过undolog实现。
持久性:通过redolog实现。
隔离性:通过加锁(当前读)&MVCC(快照读)实现。
一致性:通过undolog、redolog、隔离性共同实现。
二、快照读和当前读
快照读: 读取的是记录数据的可见版本(有旧的版本)。不加锁,普通的select语句都是快照读,如:
select * from core_user where id > 2;当前读:读取的是记录数据的最新版本,显式加锁的都是当前读
select * from core_user where id > 2 for update; select * from account where id>2 lock in share mode;
三、Read View
l Read View是什么呢? 它就是事务执行SQL语句时,产生的读视图。实际上在innodb中,每个SQL语句执行前都会得到一个Read View。
l Read View有什么用呢? 它主要是用来做可见性判断的,即判断当前事务可见哪个版本的数据~
Read View是如何保证可见性判断的呢?我们先看看Read view 的几个重要属性
l m_ids:当前系统中那些活跃(未提交)的读写事务ID, 它数据结构为一个List。
l min_limit_id:表示在生成Read View时,当前系统中活跃的读写事务中最小的事务id,即m_ids中的最小值。
l max_limit_id:表示生成Read View时,系统中应该分配给下一个事务的id值。
l creator_trx_id: 创建当前Read View的事务ID
Read view 匹配条件规则如下:
1. 如果数据事务ID trx_id < min_limit_id,表明生成该版本的事务在生成Read View前,已经提交(因为事务ID是递增的),所以该版本可以被当前事务访问。
2. 如果trx_id>= max_limit_id,表明生成该版本的事务在生成ReadView后才生成,所以该版本不可以被当前事务访问。
3. 如果 min_limit_id =<trx_id< max_limit_id,需要分3种情况讨论
l (1).如果m_ids包含trx_id,则代表Read View生成时刻,这个事务还未提交,但是如果数据的trx_id等于creator_trx_id的话,表明数据是自己生成的,因此是可见的。
l (2)如果m_ids包含trx_id,并且trx_id不等于creator_trx_id,则Read View生成时,事务未提交,并且不是自己生产的,所以当前事务也是看不见的;
l (3).如果m_ids不包含trx_id,则说明你这个事务在Read View生成之前就已经提交了,修改的结果,当前事务是能看见的。
四、什么是MVCC ?
mvcc,也就是多版本并发控制,是为了在读取数据时不加锁来提高读取效率和并发性的一种手段。
数据库并发有以下几种场景:
读-读:不存在任何问题。
读-写:有线程安全问题,可能出现脏读、幻读、不可重复读。
写-写:有线程安全问题,可能存在更新丢失等。
mvcc解决的就是读写时的线程安全问题,线程不用去争抢读写锁。
mvcc所提到的读是快照读,也就是普通的select语句。快照读在读写时不用加锁,不过可能会读到历史数据。
还有一种读取数据的方式是当前读,是一种悲观锁的操作。它会对当前读取的数据进行加锁,所以读到的数据都是最新的。主要包括以下几种操作:
l select lock in share mode(共享锁)
l select for update(排他锁)
l update(排他锁)
l insert(排他锁)
l delete(排他锁)
五、mvcc如何实现RC和RR的隔离级别
(1)RC的隔离级别下,每个快照读都会生成并获取最新的readview。
(2)RR的隔离级别下,只有在同一个事务的第一个快照读才会创建readview,之后的每次快照读都使用的同一个readview,所以每次的查询结果都是一样的。
开始事物时创建readview, readview维护当前活动的事物id, 即未提交的事物id, 排序生成一个数组, 访问数据, 获得数据中的事物ID(获取的是事物id最大的记录), 对比readview
如果在readview的左边(比readview 小), 可以访问(在左边意味着事物已经提交)
如果在readview的右边(比readview大), 或者在readview 中, 不可以访问, 获取roll_pointer, 取上一版本重新对比(在右边意味着, 该事物在readview生成之后出现, 在readview中意味着该事物还未提交)