【mysql】mysql事务隔离级别、MVCC
sql事务隔离级别
事务并发四个问题:
- 脏写:如果一次事务修改了另一个未提交事务修改过的数据,就意味着发生了脏写现象
- 脏读:如果一个事务读到另一个未提交的事务修改过的数据,就意味着发生了脏读
- 不可重复读:如果一个事务先读取了一个记录,另外一个事务对该记录进行了修改,当前事务再次读该记录时数据不一致,就意味着发生了不可重复读
- 幻读:如果一个事务某些搜索体哦阿健查询出一些记录,在该事务未提交时,宁外一个事务写入了一些记录,就发生了幻读
sql四个隔离级别:
无论哪种隔离级别,都不允许脏写发生
- 读未提交:三个问题都没解决
- 读已提交:不可能发生脏读 | 可能发生不可重复读 | 可能幻读
- 可重复读:不可能发生脏读 | 不可能发生不可重复读| 可能幻读
- 可串行化:都能解决
MVCC
InnoDB会生成两个隐藏字段 trx_id & roll_pointer
在每次跟新记录后都会将旧值放到一条 undo 日志中,所有的版本都会被roll_pointer链接成一个链表(头插法),称为版本链。每个版本链的头节点都是当前记录的最新值,每个版本链会包含生成该版本的事务ID。利用这个版本链来控制并发事务的访问相同记录时的行为,称为多版本并发控制。
ReadView
何时生成readview?
-
在读已提交隔离级别下,是每个SELECT都会获取最新的read view;
-
而在可重复读隔离级别下,则是当事务中的第一个SELECT请求才创建read view。
对于读已提交和可重复读,都必须保证自己读到、可见的都是已提交事物的记录
判断哪个版本的事务可见,设计了ReadView(一致性视图),包含了四个内容
- m_ids:当前系统中活跃的读写事务的id列表
- min_trx_id:当前系统中活跃的读写事务最小的事务id即m_ids中的最小值
- max_trx_id:系统应该分配给下一个事务的事务id值
- creator_trx_id:生成该ReadVidw的事务的事务id
判断访问某条记录是否可见:
- 如果被访问版本的trx_id 和 ReadView 中的creator值相同,则证明这当前事务访问它自己修改过的记录,所以该版本可见
- 如果被访问版本的trx_id属性值小于ReadView中的min_trx_id,表明版本事务已提交,所以可见。
- 如果被访问版本的trx_id属性值在ReadView的min_trx_id和max_trx_id之间,则需要判断trx_id是否早m_ids列表中
- 如果在则证明该事务是活跃的,不可见
- 反之,则可见
- 如果被访问版本的trx_id属性值大于等于max_trx_id,则表明该版本的事务实在当前事务生成ReadView后才开启的,所以不可见。
如果某个版本的数据对当前不可见,就顺着版本链找到下一个版本的数据,直到找的可见数据,如果最后一个版本也不可见,则意味着当前事务对该记录完全不可见,查询结果不包含该记录。
因为可重复读隔离条件下,只会生成第一次select的readview,所以解决了 不可重复读这一问题;读已提交每次都会生成,所以没解决。
总结
所谓的MVCC是指在使用 可重复读 和读已提交 这两种隔离级别的事务执行普通的SELECT操作时,通过read-view机制与undo版本链比对机制,使得不同的事务会根据数据版本链对比规则读取 。这样可以使不同事务的 读-写、写读操作并发执行,从而提升系统性能。