Mysql 事务、幻读、当前读、快照读相关笔记

1 事务的基础知识
  • 事务的四大特性(ACID)

    • 原子性:事务的最小工作单元,要么全成功,要么全失败。
    • 一致性:事务开始和结束后,数据库的完整性不会被破坏。
    • 隔离性:不同事务之间互不影响。
    • 持久性:事务提交后,对数据的修改是永久性的,即使系统故障也不会丢失。
  • 事务隔离级别

    • 读未提交:一个事务还未提交,它做的变更能被其它事务读到。
    • 读提交:一个事务提交后,变更才能被其它事务看到。Oracle默认此隔离级别
    • 可重复读:一个事务执行过程中看到的数据总是和这个事务开始启动时看到的数据是一致的。当然未提交的事务对其它事务也是不可见的。Mysql默认此隔离级别
    • 串行化:同一行记录读写都会加锁,后开启的事务必须要等前一个事务执行完成。
  • 事务隔离级别处理的问题

    • 脏读:一个事务读取到了另外一个未提交事务修改的数据。读提交可避免脏读
    • 幻读:一个事务中使用相同的SQL进行两次读取,第二次读取到了其它事务插入的行。Mysql默认可重复读,可以处理幻读,幻读在当前读下才会出现,通过间隙锁来处理
    • 不可重复读:一个事务内多次读取的结果不一样。可重复读可以避免脏读和不可重复读
2 Mvcc如何实现事务隔离级别的(快照读)

快照读:不加锁的普通Select语句 通过Mvcc实现

当前读:update、insert、delete和select … lock in share mode和select … for updte next-key锁(行锁+gap锁)实现

InnoDB的Mvcc是通过在每行记录后面保存两个隐藏的列来实现的。一个保存了行的事务ID(DB_TRX_ID),一个保存了行的回滚指针(DB_ROLL_PT)。每开始一个新的事务,都会自动递增产生一个新的事务id。事务开始时会把事务id放到当前事务影响的行事务id中,当查询时需要用到当前事务id和每行记录的事务id进行比较。

在Mysql默认可重复读的隔离级别下,MVCC对不同语句的处理如下:

  • SELECT
    • InnoDB只查找版本早于当前事务版本的数据行(也就是行的事务id小于或者等于当前事务id),这样可以确保事务读取的行要么是事务开始前已经存在的要么是事务自身插入或者修改过的。
    • 删除的行要事务id判断,读取到的事务开始之前状态的版本。只有符合上述两个条件的记录,才能作为查询结果。
  • INSERT
    • InnoDB位新插入的每一行保存当前事务id作为行记录事务id。
  • DELETE
    • InnoDB为删除的每一行保存当前事务id作为行删除标识。
  • UPDATE
    • InnoDB为插入一行新纪录,保存当前事务id作为行事务id,同事保存航前事务id到原来的行作为行删除标识。

MVCC在Mysql中实现依赖的是undo log 和read view

  • update或者delete操作中产是的undo log因为对已经存在的记录产生影响,为了提供MVCC机制,因此update undo log 不能在事务提交时就进行删除,而是将undo log放到history list中,等待purge线程(主要任务是将数据库中已经mark del 的数据删除,另外也会批量回收undo pages)进行最后的删除操作。事务的每一次修改当前行数据的时候都会在在更新后的数据的回滚指针中指向修改前的数据。
  • ReadView
    • 对于读未提交所有事务都是读取数据库最新值即可,对于串行化的隔离级别所有请求都会加锁,不需要通过MVCC实现。
    • 读已提交:每次事务中的读取都会单独生成一个独立的ReadView,所以当前隔离级别下就能读取到其它事务已提交的变更。
    • **可重复读:**只会在事务开启的时候创建一个ReadView,多次查询都会从这个ReadView中获取,所以同一个事务中读取到的数据是一致的。
3 当前读

Mysql的当前读是通过间隙锁来实现的,默认隔离条件下能够处理幻读。

锁算法:(InnoDB行锁是通过对索引数据页的记录加锁实现的)

  • 行锁(Record Lock):锁直接加在索引上
  • 间隙锁(Gap Lock):是innodb在可重复读隔离级别下处理幻读的解决方案。锁定索引记录间隙,确保索引记录间隙不变。
  • Next-Key Lock:行锁和间隙锁的组合,同属锁住数据和前后间隙。前开后闭。

加锁规则:

  • 原则1:加锁基本单位是next-key lock
  • 原则2:查找过程中访问到的对象才会加锁
  • 优化1:索引上的等值查询,给唯一索引加锁的时候next-key lock会退化成行锁
  • 优化2:索引上的等值查询,向右遍历时且最后一个值不满足等值条件的时候,next-key lock退化成间隙锁
  • 无索引加锁时,会导致全表锁定。

Mysql默认隔离级别可重复读的场景下,会通过间隙锁(行锁间隙锁next-key lock都使用到)来处理幻读可重复读的场景下只会使用行锁。

Mysql默认隔离级别为可重复读的原因:

  • 只有可重复读的场景支持间隙锁,才能处理当前读下的幻读问题,因为Mysql主从复制的过程时通过 bin log进行数据同步的,早期的Mysql只有statement这种格式的bin log,会记录SQL的原文,当事务乱序的时候会导致备库SQL回放之后主从数据不一致。(如果改成可重复读为了处理主从不一致需要把bin log格式设置为row)

读提交比可重复读的性能好的原因:

  • 读提交加锁过程中不需要添加间隙锁和next-key lock,只需要对修改的记录添加行锁即可。
  • 读提交还支持半一致读,大大减少更新语句时行锁的冲突,对于不满足更新条件的记录可以提前释放,提升并发。
  • 加锁范围小,死锁的几率变小。
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值