MySQL事务隔离级别和MVCC

01/25 09:00
阅读数 31

Springboot设置事务隔离等级
1、@EnableTransactionManagement 来启用注解式事务管理
2、@Transactional(isolation = Isolation.DEFAULT,propagation = Propagation.REQUIRED)设置事务隔离级别和传播行为


这两篇文章可以结合起来一起理解:
面试官:谈谈你对Mysql的MVCC的理解?
这一篇我觉得是写MVCC写的最好的一篇:
Innodb中的事务隔离级别和锁以及MVCC之间的关系
MVCC的意义只是替代读锁,写依旧是加锁的,这样避免了脏写
MVCC不可以避免幻读。(但是有的文章说mvcc防住了幻读,没防住是因为把快照读提升到了当前读的模式)
如果要避免幻读,可以使用MVCC+间隙锁的方式。






MySQL 到底是怎么解决幻读的?
快照(ReadView)读的幻读-mvcc 解决
当前读的幻读-Next-Key锁解决

当前读与快照读
首先读分为:
快照读
select * from table where ?;
当前读:特殊的读操作,插入/更新/删除操作,属于当前读,需要加锁。
select * from table where ? lock in share mode;
select * from table where ? for update;
insert into table values (…);
update table set ? where ?;
delete from table where ?;
对于快照读来说,幻读的解决是依赖mvcc解决。而对于当前读则依赖于Next-Key锁解决。










MySQL事务隔离级别和实现原理(看这一篇文章就够了!)
MySQL 中是如何实现事务隔离的

  • 首先说读未提交,它是性能最好,也可以说它是最野蛮的方式,因为它压根儿就不加锁,所以根本谈不上什么隔离效果,可以理解为没有隔离。
  • 再来说串行化。读的时候加共享锁,也就是其他事务可以并发读,但是不能写。写的时候加排它锁,其他事务不能并发写也不能并发读。
  • 最后说读提交RC和可重复读RR,是采用了MVCC (多版本并发控制)的方式
  • RR级别在一般的标准上是不能解决幻读,但是在Mysql里面已经解决了RR级别幻读的问题

并发写的时候加锁问题:
加锁的过程要分有索引无索引两种情况,比如下面这条语句
update user set age=11 where id = 1
id 是这张表的主键,是有索引的情况,那么 MySQL 直接就在索引数中找到了这行数据,然后干净利落的加上行锁就可以了。
而下面这条语句
update user set age=11 where age=10
表中并没有为 age 字段设置索引,所以, MySQL 无法直接定位到这行数据。那怎么办呢,当然也不是加表锁了。MySQL 会为这张表中所有行加行锁,没错,是所有行。但是呢,在加上行锁后,MySQL 会进行一遍过滤,发现不满足的行就释放锁,最终只留下符合条件的行。虽然最终只为符合条件的行加了锁,但是这一锁一释放的过程对性能也是影响极大的。所以,如果是大表的话,建议合理设计索引,如果真的出现这种情况,那很难保证并发度。






mysql在RR隔离级别下有MVCC,那还有共享锁吗?
回答一:对于具备多版本控制能力的数据库引擎确实不需要对表的读取加锁, MVCC能保障读取的完整性. MVCC 仅于单行(或单个字段)起作用, 锁可以实现多行多表多操作的事务锁定. 锁用途和 MVCC 是不太一样的, 可以说事务的实现依赖于 MVCC 特性, 但事务要比 MVCC 本身复杂得多. 如果不希望在读取时记录被修改, 锁才是唯一可行的。

回答二:共享锁还是存在的哦,在mysql5.6 innodb,RR隔离级别中。
使用主键索引去查询一条不存在的数据,就会加上s锁了。
你可以试一下:
开启两个事务用主键查询同一条不存在数据(使用select … for update)。
两个事务都会返回一个空结果。
此时,两个事务无论是谁都没办法以这个主键insert数据。





深入分析事务的隔离级别----非MySQL的处理方法,标准SQL事务规定的处理方法,用锁处理的


Redo log, bin log, Undo log

InnoDB中通过undo log实现了数据的多版本,而并发控制通过锁来实现。

undo log除了实现MVCC外,还用于事务的回滚。MySQL Innodb中存在多种日志,除了错误日志、查询日志外,还有很多和数据持久性、一致性有关的日志。

binlog,是mysql服务层产生的日志,常用来进行数据恢复、数据库复制,常见的mysql主从架构,就是采用slave同步master的binlog实现的, 另外通过解析binlog能够实现mysql到其他数据源(如ElasticSearch)的数据复制。

redo log记录了数据操作在物理层面的修改,mysql中使用了大量缓存,缓存存在于内存中,修改操作时会直接修改内存,而不是立刻修改磁盘,当内存和磁盘的数据不一致时,称内存中的数据为脏页(dirty page)。为了保证数据的安全性,事务进行中时会不断的产生redo log,在事务提交时进行一次flush操作,保存到磁盘中, redo log是按照顺序写入的,磁盘的顺序读写的速度远大于随机读写。当数据库或主机失效重启时,会根据redo log进行数据的恢复,如果redo log中有事务提交,则进行事务提交修改数据。这样实现了事务的原子性、一致性和持久性。

undo log: 除了记录redo log外,当进行数据修改时还会记录undo log,undo log用于数据的撤回操作,它记录了修改的反向操作,比如,插入对应删除,修改对应修改为原来的数据,通过undo log可以实现事务回滚,并且可以根据undo log回溯到某个特定的版本的数据,实现MVCC。


展开阅读全文
打赏
0
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
0
分享
返回顶部
顶部