1.脏读、不可重复读、幻读的区别
- 脏读是指当一个事务正在访问数据,并且对数据进行了修改,但是修改还没有提交到数据库中,这时另一个事务也访问 这个数据,然后使用了这个没有提交的数据。
- 不可重复读是指在一个事务内,多次读同一数据。在这个事务还没有结束时,另一个事务访问该数据并修改。那么,在第一个事务中的两 次读数据之间,由于第二个事务的修改,第一个事务两次读到的的数据可能是不一样的。
- 幻读是在一个事务执行期间,读取了其他事务新增或者的数据,导致前后读取到的行数不一致
参考文章:
- https://cloud.tencent.com/developer/article/1450773
- https://www.php.cn/mysql-tutorials-459597.html
2.怎么解决幻读
- 幻读指的是一个事务在前后两次查询同一个范围的时候,后一次查询看到了前一次查询没有看到的行。
- MySQL 默认的隔离级别是可重复读,在此隔离级别下为了解决“幻读”问题:“快照读”依靠MVCC控制,“当前读”通过间隙锁解决。
select * from t where a=1;属于快照读
select * from t where a=1 for update;属于当前读
快照读
当读取的某一行被其他事务锁定时(也就是有其他事务正在改这行数据),它可以从 undo log 中分析出该行记录以前的数据是什么,从而提供该行版本信息,让用户进行快照读。在可重复读的隔离级别下,从 undo log 中读取的数据总是事务开始时的快照数据(也就是版本号小于当前事务 ID 的数据),在提交读的隔离级别下,从 undo log 中读取的总是最新的快照数据(也就是比正在修改这行数据的事务 ID 修改前的数据。)。
原理:将历史数据存一份快照,所以其他事务增加与删除数据,对于当前事务来说是不可见的。
当前读
因为 MySQL 的默认隔离级别是可重复读,在这种情况下,执行 SELECT...FOR UPDATE
查询语句是,会申请行锁,那么加锁区间其实是**(负无穷,1](1,正无穷**).。两个加锁区间都可能有数据满足条件,所以会申请行锁中的 next-key lock,对上面这两个区间都加锁,这样其他事务不能往这两个区间插入数据,其他事务执行插入时会一直等待获取锁,直到此事务提交,释放行锁,其他事务才有可能申请到锁,然后进行插入。这样就解决了幻读问题。
原理:将当前数据行与上一条数据和下一条数据之间的间隙锁定,保证此范围内读取的数据是一致的。
参考文章:
- https://cloud.tencent.com/developer/article/1437615
- https://xie.infoq.cn/article/6abc55424169c68e89efed08d
3.undo log是什么
数据库事务四大特性中有一个是原子性 ,就是指对数据库的一系列操作,要么全部成功,要么全部失败,不可能出现部分成功的情况。实际上,原子性底层就是通过 undo log 实现的。undo log主要记录了数据的逻辑变化,比如一条 INSERT 语句,对应一条DELETE 的 undo log ,对于每个 UPDATE 语句,对应一条相反的 UPDATE 的 undo log ,这样在发生错误时,就能回滚到事务之前的数据状态。同时, undo log 也是 MVCC(多版本并发控制)实现的关键。
- 回滚数据:当数据发生异常错误时,根据执行 undo log 就可以回滚到事务之前的数据状态,保证原子性。
- MVCC 一致性视图:通过 undo log 找到对应的数据版本号,是保证 MVCC 视图的一致性的必要条件。
4.redo log是什么
事务的四大特性里面有一个是 持久性 ,具体来说就是只要事务提交成功,那么对数据库做的修改就被永久保存下来了,不可能因为任何原因再回到原来的状态 。如果在每次事务提交的时候,将该事务涉及修改的数据页全部刷新到磁盘中,做会有严重的性能问题:
- 因为 Innodb 是以 页 为单位进行磁盘交互的,而一个事务很可能只修改一个数据页里面的几个字节,这个时候将完整的数据页刷到磁盘的话,太浪费资源了。
- 一个事务可能涉及修改多个数据页,并且这些数据页在物理上并不连续,使用随机IO写入性能太差。
因此 mysql 设计了 redo log , 具体来说就是只记录事务对数据页做了哪些修改,这样就能完美地解决性能问题了(相对而言文件更小并且是顺序IO)。
redo log 是重做日志,属于 InnoDB储存引擎的日志。是物理日志,日志记录的内容是数据页的更改,这个页"做了什么改动"。如:add xx记录 to Page1,向数据页Page1增加一个记录。
redo log 包括两部分:一个是内存中的日志缓冲(redo log buffer),其是易失的。二是重做日志文件(redo log file),其是持久的。
mysql 每执行一条 DML 语句,先将记录写入 redo log buffer,后续某个时间点再一次性将多个操作记录写到 redo log file。这种 先写日志,再写磁盘 的技术就是 MySQL 里经常说到的 WAL(Write-Ahead Logging) 技术。
5.bin log是什么
binLog。记录了对Mysql数据库执行更改的所有操作,但是不包括查看的操作(SELECT 和 SHOW这类操作)。以二进制的形式保存在磁盘中。是属于Mysql Server层记录,任何存储引擎的 mysql 数据库都会记录binlog日志。并且binlog 还是 mysql 的逻辑日志。
- 逻辑日志:可以简单理解为记录的就是sql语句 。
- 物理日志:mysql 数据最终是保存在数据页中的,物理日志记录的就是数据页变更 。
在实际应用中, binlog 的主要使用场景有两个,分别是 主从复制 和 数据恢复 。
- 主从复制 :在 Master 端开启 binlog ,然后将 binlog发送到各个 Slave从 端, Slave 端重放 binlog 从而达到主从数据一致。
- 数据恢复 :通过使用 mysqlbinlog 工具来恢复数据。
6.3种日志的联系
- binlog是属于mysql Server层的,属于整个mysql的
- redo log、undo log是属于innodb存储引擎独有的
- redo log、undo log是事务日志,binlog是二进制日志负责记录对mysql数据库有修改的sql操作。
参考文章:
- https://cloud.tencent.com/developer/article/1695604
- https://www.cnblogs.com/semi-sub/p/14225047.html
- 极客时间《MySQL45讲》
如有侵权请联系删除