事务的四个特性ACID

    • 原子性
    • 一致性
    • 隔离性
    • 持久性

    image.png

    MVCC:多版本并发控制,解决数据并发读写问题
    MVCC多版本并发控制指的是维持一个数据的多个版本,使得读写操作没有冲突。快照读是mysql为了实现MVCC的一个非阻塞读功能。

    MVCC实现原理
    一行数据后面会有隐藏字段。

    • DB_TRX_ID(最近修改事务ID,记录创建当前记录或者最后一个修改的事务ID)
    • DB_ROLL_PTR(回滚指针,指向这条记录的上一个版本)
    • DB_ROW_ID(隐藏主键)

    image.png
    一行数据的字段:
    image.png
    undolog:
    回滚日志,实际记录的是之前数据行的历史版本。是一个逻辑日志。
    undolog的生成过程:
    image.png
    在事务对某一行数据进行修改后,就要将之前的数据行记录到undo日志中。
    image.png
    undolog会形成一个链表,链首存储的是最新的旧纪录,而链尾放的是最旧的旧日志。
    undolog不会无限膨胀下去,会存在要给prege线程,当发现当前记录不需要回滚,或者是不需要参与到MVCC就会将数据进行删除。

    readview:
    当事务在进行快照读的时候,会生成一个读视图,来进行可见性判断,可见性判断是由可见性算法来确定的
    表示其他事务能否读取到本事务的数据
    有几个字段:

    • trx_list:当前系统活跃的事务ID
    • up_limit_id:活跃事务列表中最小的ID值
    • low_limit_id:当前系统尚未分配的下一个事务ID

    例子:
    image.png
    分析:
    image.png
    参照可见性算法:
    image.png

    这个要先考虑隔离级别,在不同的隔离级别下,会有不同的结果
    RC:提交读。 能
    RR:可重复读。能

    image.png

    RC:提交读。能
    RR:未提交读。不能

    分析:
    image.pngimage.png
    即使执行了第二个select对应的也是用的第一个select生成的视图
    重点:
    能否看到修改的数据,取决于可见性算法,可见性算法比较的时候取决于readview中的结果值
    两种情况的差异是因为在不同的隔离级别的时候,生成readview的时机是不同的。
    如果是RC隔离级别,每次执行快照读都会生成新的readview
    如果是RR隔离级别,只有在当前事务第一次进行快照读对的时候生成readview。之后的快照读操作都会用当亲的readview。
    幻读问题的解决是因为间隙锁,而不是因为MVCC,MVCC可能会导致幻读
    幻读就是两次读出来的数据行总数不同。
    image.png
    出现幻读问题
    image.png
    出现了三条记录。

    结论:
    如果当前的所有操作都是当前读,那么是不会产生幻读问题,只有当前读和快照读一起使用的时候才会产生幻读问题

    解决办法就是加锁。
    image.png
    加了锁之后。右边数据被阻塞了。

    锁的理解:
    不同维度来区分
    锁的粒度来分

    • 行锁
    • 表锁
    • 页锁

    按照读写来分

    • 共享锁(读锁)
    • 排它锁(写锁)

    实际是否加锁来分:

    • 乐观锁不加锁
    • 悲观锁加锁

    意向锁是属于表锁的一类:

    • 记录锁
    • 间隙锁
    • 临建锁

    image.png