• 重新认识mysql事务


    文章内容参考https://mp.weixin.qq.com/s/v0e3xqzR7ftFXurG_U8XYA

    在此基础上的个人整理

    MySQL事务

    什么是事务

    mysql中,事务其实就是最小的不可分割的工作单元,事务能够保证一个业务的完整性。

    事务:一个最小的不可再分的工作单元

    通常一个事务对应一个完整的业务(例如银行账户转账业务,该业务就是一个最小的工作单元)一个完整的业务需要批量的DML(insert、update、delete)语句共同联合完成事务只和DML语句有关,或者说DML语句才有事务。这个和业务逻辑有关,业务逻辑不同,DML语句的个数不同

    事务的特征(ACID)

    • 原子性(A/atomicity):事务是最小单位,不可再分,多条DML要么同时成功,要么同是失败。
    • 一致性(C/consistency):事务要求所有的DML语句操作的逻辑与操作结束后的数据保持一致。这也是事务的目的。
    • 隔离性(I/isolation):事务A和事务B之间具有隔离性
    • 持久性(D/durability):是事务的保证,事务终结的标志(内存的数据持久到硬盘文件中)

    原子性

    原子性即为不可分割的最小单元,保证多条DML语句要么同是成功,要么同是失败,底层使用undo log来保证,undo log记录着事务发生前和事务发生后的多份数据

    隔离型

    多个事务并发时,互不干扰,如果多个事务同时操作相同的数据,那么就对产生对应的脏读,不可重复度,幻读的问题。所以innodb提供了4种事物隔离级别,如下:

    • 读未提交(read uncommit)
    • 读已提交(read commit)
    • 可重复度(repeatable read)
    • 串行(serializable)

    不同隔离级别的本质实际上都是通过锁来解决的,innodb为了保证事务的一致性,只要写数据,都会加入排他锁

    读未提交

    读不加锁,那么其他事务在对数据进行操作但又未提交时,即便其他事务对数据加入了排他锁,但是读取数据时没有加锁,自然的就不会形成隔离效果,当前事务就会读取到其他事务修改的内容,即产生了脏读

    试想:如果上述情况读数据时加了锁,那么读请求就会阻塞,则查询性能变得很差

    为了提升并发性能,innodb使用了多版本并发控制(Multi-Version Concurrency Control,MVCC)来解决。MVCC通过生成数据快照(Snapshot),并用这个快照来提供一定级别(语句级或事务级)的一致性读取

    读已提交

    MVCC使用undo log + ReadView实现

    在这里插入图片描述

    undo log中事务的修改都会生成 一条新数据,新数据中记录的修改内容,以及额外记录由哪个事务做的修改和修改前上一条数据的指向

    在读已提交中,使用语句级快照来实现,即每一次查询时,都会生成快照ReadView,ReadView中保存了正在进行中的事务的id,那么在查询数据时,通过判断undo log当前读取到的数据的事务id是否在ReadView中,如果不在则查询成功,如果在就查询roll_pointer中保存的上一次的数据引用,通过这种方式来做到避免读取尚未提交的事务中的数据

    读已提交造成的问题就是不可重复读。即当前事务先读取到了数据A,另外一个事务将A改成B,并提交事务,此时当前事务再次读取,则读取到的内容为B,导致一个事务对相同的数据查询两次结果不一致,这就是不可重复读

    可重复读

    可重复度的隔离级别解决了不可重复读的问题,本质上是因为可重复度的ReadView快照在当前事务开启的时候生成(事务),再当前事务没提交之前都不会再次生成快照,进而解决了不可重复读。

    而不可重复读会导致幻读问题,幻读指的是当前事务的读会受到其他事务已经提交成功的新增或删除行为的影响

    时间事务1事务2
    T1begin;
    T2select * from test;
    T3insert into test value(3,33);
    T4select * from test;
    T5update test set name=‘333’ where id = 3;
    T6select * from test;
    T7commit;
    1. 事务1开启事务,select只有两行记录,在T3时刻,事务2插入一条数据并且马上提交,在T4时刻再次select读到与T2时刻一样的数据,到这是没有问题的,满足可重复读。
    2. 在T5时刻update一条没有的数据,却执行成功了,在T6时刻select却发现多了一个记录,这就出现幻读的现象。

    串行

    不允许事务并发,全都按照顺序执行,性能最差

    持久性

    持久性指的是事务只要提交完成,那么对于磁盘来说就是永久性的修改

    在mysql的处理逻辑中,数据并不是没发生修改就立即持久化到磁盘中,为了提高性能,修改会立马在内存中生效,然后按照一定的刷盘策略同步到磁盘上,那么内存中修改完成后但未持久化到磁盘的过程中mysql发生宕机,在mysql重启后依旧能够保持数据持久性,就是因为在内存中更新的同时,会将具体的修改内容保存到redo log

    直接在磁盘修改真实数据,属于随机写,需要找到写入的地方,速度偏慢,redo log中记录的是将某page做了某修改,并且是顺序写,写入速度很快,并且文件很小,恢复也很快

    一致性

    一致性即使用事务的目的,原子性、隔离型、持久性都是为了保证一致性的手段,一致性需要由程序来保证

    比如当出现了异常情况,那么程序需要保证事务的回滚,无异常时,需要手动提交事务

  • 相关阅读:
    记录一次Powerjob踩的坑(Failed to deserialize message)
    云原生部署手册01:构建k8s集群并配置持久化存储
    因为manifest.json文件引起的 android-chrome-192x192.png 404 (Not Found)
    链表经典面试题(四)
    Spark生产环境高效读写My SQL(df,rdd)
    springBoot--web--函数式web
    github要求提供双重认证 (2FA), 终于试成功
    【数据库系统概论】触发器
    Python_面向对象编程
    慢SQL,压垮团队的最后一根稻草!
  • 原文地址:https://blog.csdn.net/qq1010830256/article/details/125403852