MYSQL-事务

131 阅读4分钟

事务

MYSQL四大特性

ACID

  • ATOMIC:原子性,由UNDO LOG日志保证的
  • CONSISTENCE:一致性体现在 事务开始和结束 完整性得到保证,与现实的一致性,两个人银行转账的案例

ISOLATION:隔离性,由MVCC版本链和锁保证的

DURABILITY:持久性,由MYSQL的两段提交设计、REDO LOG日志和BIN LOG日志保证的

MYSQL事务和REDIS事务有什么区别?

  • REDIS事务无法保证持久性,首先RDB快照写,是按照配置文件或者指定命令在特定时间才会写,AOF设置为ALWAYS,是先将数据放到AOF缓冲中,再写入,可能会出现丢死上一个事件循环中的数据的情况。
  • REDIS无法保证原子性,无法回滚,主要命令有MULTI EXEC,开启事务能加快批量操作。

MYSQL事务隔离级别有哪些?分别解决什么问题?

  • 事务级别对照表
事务级别可能出现的并发问题如何解决
读未提交脏读、不可重复读、幻读
读已提交不可重复读、幻读MVCC版本链
可重复读幻读MVCC+ReadVIEW+=临键锁
串行化全是当前读,没有MVCC
  • 并发问题说明:

    • 脏读:A事务读到B事务未提交的数据
    • 不可重复读:强调读到了B事务修改的数据,A事务多次读取记录,在这个过程中B事务修改了数据并提交,导致A事务多次读的结果不一样
    • 幻读:强调读到了B事务新增的数据,A事务多次读取记录,在这个过程中B事务新增了数据并提交,导致A事务读到的记录数不一样

什么是MVCC?

  • MVCC是多版本并发控制,通过记录历史版本数据,解决读写并发冲突问题,避免加锁,提高MYSQL并发性能。
  • 在行记录中,有事务ID和ROLL_PTR,MYSQL将历史数据存在UNDO LOG日志里面,ROLL_PTR指向UNDO_LOG日志,每次SELECT的时候会创建READVIEW快照,通过当前事务ID与历史数据比较,判断哪一条UNDO LOG可见。

MVCC中READVIEW可见性的规则?

  • READVIEW主要有四个字段:创建这条记录的事务ID、所有活跃未提交的事务IDS、活跃未提交的最小事务ID、下一个事务ID
  • 如果记录的事务id小于ids 就说明这条记录已提交
  • 如果记录的事务id在ids中,就说明这条记录未提交
  • 如果记录的事务id大于ids,就说明这事务还没开始

读已提交和可重复读在MVCC上有什么区别?

主要区别是生成READVIEW的时机不同

  • 读已提交,每次执行SELECT 都会生成一次READVIEW数据,然后通过MVCC,只读取事务id小于活跃未提交事务ids中的记录
  • 可重复读,只在事务开始之前生成一次READVIEW,在本次事务中一直用这个READVIEW

MYSQL的默认隔离级别是什么?怎么实现的?

默认隔离级别是可重复读,是通过MVCC(每个事务唯一的事务id,修改在undo-log链里面)+当前读上加快照读+行级锁:间隙锁

为什么很多互联网公司使用读已提交隔离级别?

因为MYSQL读已提交是通过MVCC版本链实现的,更新数据没有间隙锁,可以减少死锁的几率

MYSQL是如何解决不可重复读的问题的,又是怎么解决幻读的?

  • MYSQL的读取有两种方式,快照读:就是直接的SELECT ... ,当前读:SELECT ... FOR UPDATE
  • 快照读的情况下,MYSQL可以直接利用MVCC+READVIEW来实现,事务创建之前就做一次快照读,之后所有的操作都在快照的undo里面,保证可重复读
  • 当前读的情况下,就没办法用MVCC+READVIEW了,所以这时候就要加间隙锁来解决,因为间隙锁和插入意向锁不兼容,所以也一部分解决了幻读的问题。

可重复读为什么没有完全解决幻读的问题?

  • 可重复读为了当前读实现可重读 所以选择了间隙锁的方式,一定程度上解决了幻读,因为间隙锁只能阻塞其他事务,比如以下场景

    • A事务先进行快照读,没有加锁
    • B事务插入了一条id=5的数据
    • A事务更新id=5的数据,A事务更新会执行当前读,所以能读到id=5,更新完了之后,id=5的事务id就是A
    • A再进行快照读,因为快照读是通过版本链进行的,所以这时候读到了B事务的数据
  • 总结:

    • 两次都是快照读就不会幻读,但第一次快照读,中间发生一次当前读,那就会造成幻读。