1、事务隔离级别:

        在一次事务里面,多次查询之后,结果集的个数不一致的情况叫做幻读。而多或者少的那一行被叫做幻行,也就是说当一个事务在进行读取数据的时候,其他事务对该数据进行了改变。在高并发数据库系统中,需要保证事务与事务之间的隔离性,还有事务本身的一致性。

         脏读:比如A事务读取到了B事务还没有提交的数据,因为什么原因B事务回滚了,那么A事务读取的数据和数据库中的数据不同,也就是读到了其他事务没有提交的数据。

         读取已提交会产生不可重复读:比如A事务读取数据,开始是100,事务还没有提交,此时B事务对这个数据修改为80,然后提交了事务,此时A事务再次读取就是80,因为B已经提交了,但是两次的结果不一样,就产生了不可重复读的现象。

        可重复读:在可重复读中,该sql第一次读取到数据后,就将这些数据加锁(悲观锁),其它事务无法修改这些数据,就可以实现可重复读了。但这种方法却无法锁住insert的数据。 

        Mysql中读的操作是通过MVCC实现的,如果A事务读取数据,B事务修改了数据提交了,因为MVCC是根据事务粒度生成的ReadView所以不会读取到B事务修改的数据。

        比如:A事务读取数据,所以当事务A先前读取了数据,或者修改了全部数据,事务B还是可以insert数据提交,这时事务A就会发现莫名其妙多了一条之前没有的数据,这就是幻读,不能通过行锁来避免。需要Serializable隔离级别 ,读用读锁,写用写锁,读锁和写锁互斥,这么做可以有效的避免幻读、不可重复读、脏读等问题,但会极大的降低数据库的并发能力。

但是MySQL、ORACLE、PostgreSQL等成熟的数据库,出于性能考虑,都是使用了以乐观锁为理论基础的MVCC(多版本并发控制)来实现。

        Mysql的默认隔离级别是可重读,可产生幻读的:幻读仅专指  新插入的行,且在当前读的情况下。

        比如:A事务中读取有一条数据是100,B事务中修改为了80,且插入了一条数据,变成了两条事务提交。此时A事务读取的依旧是100,一条数据,但是A事务往里边插入第二条数据的时候,id和B事务插入的数据一样,id是一样的,此时A事务插入不进去,主键冲突,但是查询的时候依旧差不到,这就是幻读的一个例子。

        比如:A事务中读取大于5的数据有3条,B事务插入了一条,提交,A事务再次查询大于5的数据发现是4条,就产生了幻读。

2、MVCC以及RC、RR:

        MVCC Multi-Version Concurrency Control 就是一个多版本并发控制,即多个不同版本的数据实现并发控制的技术,其基本思想是为每次事务生成一个新版本的数据,在读数据时选择不同版本的数据即可以实现对事务结果的完整性读取,从而不用竞争锁,提高性能这种读是属于快照读,不是当前读,当前读需要加锁,悲观锁。

        重要:MVCC 使每个连接到数据库的读者,在某个瞬间看到的是数据库的一个ReadView,不同的隔离级别生成快照的粒度不同,读取已提交生成ReadView的粒度是以每个select单位,所以A事务前后生成的ReadView不同。可重复读生成ReadView的粒度是以事务为粒度生成的,同一个事务只会生成一个ReadView所以避免了可重复读的问题。

        当一个 MVCC 数据库需要更新一个一条数据记录的时候,它不会直接用新数据覆盖旧数据,而是将旧数据标记为过时(obsolete)并在别处增加新版本的数据。这样就会有存储多个版本的数据,但是只有一个是最新的。这种方式允许读者读取在他读之前已经存在的数据,即使这些在读的过程中半路被别人修改、删除了,也对先前正在读的用户没有影响。这种多版本的方式避免了填充删除操作在内存和磁盘存储结构造成的空洞的开销,但是需要系统周期性整理(sweep through)以真实删除老的、过时的数据

3、Mysql在的当前读和快照读:

        快照读:读取的是记录数据的可见版本(可能是过期的数据),不用加锁,select时为快照读。MVCC实现。不需要竞争锁。

        当前读:读取的是记录数据的最新版本,并且当前读返回的记录都会加上锁,保证其他事务不会再并发的修改这条记录。update、insert、delete 都是当前读。排它锁

        

4、Mysql的默认隔离级别是可重读,但是可重复会产生幻读,Mysql是如何实现避免幻读的呢?幻读只存与插入,且是当前读

                在Mysql的Innodb引擎中默认开起了间隙锁,幻读是通过间隙锁+行锁方式解决的。

5、Mysql的锁类型:

        锁存在的意义就是为了保证事务的隔离性,防止并发产生问题,从而保证一致性。

        基于属性分类:

                共享锁 S:共享锁又称之为读锁,简称S锁,当一个事务为数据加上读锁之后,其他事务只能对该数据加读锁,而不能对数据加写锁,所以读锁和写锁是互斥的。直到所有的读锁全部释放之后其他事务才能对其进行加持写锁。共享锁的特性主要是为了支持并发的读取数据,读取数据的时候不支持修改,避免出现不可重读的问题

                排它锁 X:排它锁又称之为写锁,简称X锁。当一个事务为数据加上写锁时,其他请求将不能再为数据加任何锁,直到该锁释放之后,其他事务才能对数据进行加锁,排它锁的目的是在数据修改的时候,不允许其他事务同时修改,也不允许其他事务读取,避免了脏读数据问题

        基于锁的状态分类:

                意向共享锁:

                意向排它锁:

        基于粒度分类:重点

                表级锁:表锁指的是对整个表进行加锁,当下一个事务访问该表的数据时,必须等前一个事务释放了锁才能进行对表进行访问。粒度大,并发小。

                行级锁:行锁指上锁的时候锁住的是某一行或多行,其他事务访问同一张表时,只有被锁住的记录不能访问,其他记录可以访问。粒度小,并发高。

                记录锁:加锁后只对表中的一行记录加上了锁,也就是精准查找,条件字段是唯一索引。

                间隙锁:间隙锁是在事务加锁后其锁住的是表记录的某一个区间,当表的相邻id之间出现空隙则会形成一个区间遵循左开右闭原则。间隙锁之间不会冲突。间隙锁是在可重复读隔离级别下才会生效的。

                临建锁:

6、ACID的原理:【吊打面试官】大厂面试必问的MySQL事务ACID原理,终于有人讲清楚了!_哔哩哔哩_bilibili

        mysql将数据存储到数据库之前都是先通过日志的方式来存储数据,因为日志的存储是顺序存储,可以通过偏移量来控制或者查找,而数据库的持久化存储,是见缝插针,这样可能最大化利用磁盘空间,存储完还需要记录数据的地址,所以相比日志存储比较慢。

        原子性的实现:通过Redo logUndo log,重做和回滚。如果事务提交了,那么就会执行Redo log写到数据库,如果没有提交就会执行undo log。

        持久性:redo log实现:

 7、Mysql的日志               

        日志系统主要有redo log(重做日志)和binlog(归档日志)。redo log是InnoDB存储引擎层的日志,binlog是MySQL Server层记录的日志, 两者都是记录了某些操作的日志(不是所有)自然有些重复(但两者记录的格式不同)。

         redo log和binlog区别

  • redo log是属于innoDB层面,binlog属于MySQL Server层面的,这样在数据库用别的存储引擎时可以达到一致性的要求。
  • redo log是物理日志,记录该数据页更新的内容;binlog是逻辑日志,记录的是这个更新语句的原始逻辑
  • redo log是循环写,日志空间大小固定;binlog是追加写,是指一份写到一定大小的时候会更换下一个文件,不会覆盖。
  • binlog可以作为恢复数据使用,主从复制搭建,redo log作为异常宕机或者介质故障后的数据恢复使用。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐