nber1994



mysql-事务

August 9, 2019

事务概述

Innodb中的事务隔离级别和锁的关系 https://tech.meituan.com/innodb_lock.html

事务的实现

redo log 用来保证事务的持久性
undo log用来保证事务的一致性

redo log 和undo log并不是互为逆过程
redo log记录的是页的改动
undo log记录的是行的改动

redo log

分为两种,一种是redo缓冲区中的redo log,其是易失的
另一种是redo日志文件,是持久的

redo log作用

innodb是事务型存储引擎,通过force log at commit机制实现事务的持久化,即在事务提交之前将所有日志写入到日志文件中
redo log基本上是顺序写的,而且只有在redo log日志写入之后,调用fsync命令。所以磁盘的性能决定了sync的性能,进而决定了事务的性能
在innodb中,该日志包含两部分,redo log和undo log,redo log来实现事务的持久性,undo log来实现事务的回滚和mvcc机制

binlog与redo log区别

redolog恢复

当mysql启动时,不论上次关闭是否正常,都会重做redolog,将页面改动做回磁盘,根据checkpoint表示的LSN,重做之后的redolog

undo log

undolog用于事物的回滚,将数据改动为事务之前的状态 与redolog不同的是,undolog是存在于共享表空间的undo段

误解

undolog是逻辑日志,只记录变化量

undolog作业

一个是进行事务的回滚
另一个是实现mvcc
当一个事务读取一行信息,如果发现正在被某一事务占用,则会根据undolog读取到之前版本的信息
同时undolog也会导致redolog的产生,因为undolog也需要持久化保护

事务隔离级别

事务的四个隔离级别

innodb支持的隔离级别是repeatable read,但是innodb通过next-key lock解决了幻读的问题
所以innodb已经完全实现了事务的ACID,实现了serializeble

read commited

所有的读取都是不加锁的,数据写入,修改删除是加锁的

repeatable read

不可重复读&幻读

对于这两个概念,其实是有一定区别的,不可重复读是对于修改和删除来说的,而幻读是对于inser来说的。
sql第一次读取某行之后,将改行记录加锁,阻止其他事务读取,即可实现可重复读,但是此时如果有insert操作,
是无法阻止的,还是会出现幻读的现象,这种情况下只能使用悲观锁,读加上读锁,写加上写锁,读写互斥,这样可以避免
脏读,不可重复读,幻读的问题,这种方法会导致并发性能降低,而innodb采用了mvcc机制避免了幻读的问题

mvcc的实现

innodb会为每条记录增加一个版本信息,对应的是事务的版本号,每开启一个事务,事务的版本号就会递增
在MVCC中,

快照度和当前度

快照度读取的是历史的数据
当前度读取的是当前最新版本的数据

  1. 在mvcc中,快照读就是

    • select * from table_t where …
  2. 当前读

    • select ? from table_t for update
    • select ? from table_t lock in share mode
    • insert
    • update
    • delete 当前读其实是对于写操作来说的,当前读会存在幻读的问题,所以innodb引入了next-key锁来解决这个问题

在mysql中,此时其实会在(5,30】上加next-key锁,从而阻止了事务B的插入操作,另外innodb其实会在(30 , -∞)
上也加上gap锁,使其他事务无法在这两个区间插入操作,受限于这种方式,innodb会锁住不需要的区间

对于update操作,如果where没有命中索引,则会在全表上加上gap锁,此时所有的操作都会被阻塞
行锁防止别的事务修改或删除,GAP锁防止别的事务新增,行锁和GAP锁结合形成的的Next-Key锁共同解决了RR级别在写数据时的幻读问题。