程序员子龙(Java面试 + Java学习) 程序员子龙(Java面试 + Java学习)
首页
学习指南
工具
开源项目
技术书籍

程序员子龙

Java 开发从业者
首页
学习指南
工具
开源项目
技术书籍
  • 基础

  • JVM

  • Spring

  • 并发编程

  • Mybatis

  • 网络编程

  • 数据库

    • MySQL

      • 安装mysql
      • Mybatis查询数据部分字段显示为null,转换成”“
      • 一文搞懂MySQL索引
      • 史上最全MySQL各种锁详解
      • 间隙锁
      • 死锁
      • mysql索引为啥使用B+tree?
      • Mysql Explain工具介绍
      • MVCC
      • MySQL事务【详解-最新的总结】
        • 「数据库、数据库连接池、数据源」这些概念你真的理解了吗?
        • Mysql慢查询及优化(全网最详细!!!)
        • MySQL锁、加锁机制(超详细)—— 锁分类、全局锁、共享锁、排他锁;表锁、元数据锁、意向锁;行锁、间隙锁、临键锁;乐观锁、悲观锁
        • MySQL事务(超详细!!!)
      • Oracle

      • iotdb

      • Mongodb

    • 缓存

    • 设计模式

    • 分布式

    • 高并发

    • SpringBoot

    • SpringCloudAlibaba

    • Nginx

    • 面试

    • 生产问题

    • 系统设计

    • 消息中间件

    • Java
    • 数据库
    • MySQL
    程序员子龙
    2024-01-29
    目录

    MySQL事务【详解-最新的总结】

    # 事务

    事务是数据库管理系统(DBMS)执行过程中的一个逻辑单位(不可再进行分割),由一个有限的数据库操作序列构成(多个DML语句,select语句不包含事务),要不全部成功,要不全部不成功。

    # 事务基本特性ACID是什么?

    原子性(atomicity)

    一个事务必须被视为一个不可分割的最小单元,整个事务中的所有操作要么 全部提交成功,要么全部失败,对于一个事务来说,不能只执行其中的一部分操作。

    undo log 是InnoDB存储引擎特有的。具体的实现方式是:将所有对数据的修改(增、删、改)都写入日志(undo log)。如果一个事务中的一部分操作已经成功,但另一部分操作,由于断电/系统崩溃/其它的软硬件错误而无法成功执行,则通过回溯日志,将已经执行成功的操作撤销,从而达到全部操作失败的目的。

    undo log是逻辑日志,可以理解为:记录和事务操作相反的SQL语句,事务执行insert语句,undo log就记录delete语句。它以追加写的方式记录日志,不会覆盖之前的日志。除此之外undo log还用来实现数据库多版本并发控制(Multiversion Concurrency Control,简称MVCC)

    一致性(consistency)

    一致性是指事务将数据库从一种一致性转换到另外一种一致性状态,在事务开始之前和事务结束之后数据库中数据的完整性没有被破坏。这意味着所有相关的数据规则都必须应用于事务的修改,以保持数据的完整性。

    例如转账:A给B转账,A减去500,B增加500,减少和增加相加应该是0

    隔离性(Isolation)

    一个事务的执行不能被其他事务干扰。即一个事务内部的操作及使用的数据 对并发的其他事务是隔离的,并发执行的各个事务之间不能互相干扰。数据库系统提供一定的隔离机制,保证事务在不受外部并发操作影响的“独立”环境执行。这意味着事务处理过程中的中间状态对外部是不可见的,反之亦然。

    如果隔离性不能保证,会导致什么问题?

    张三借给李四生活费,借了两次,每次都是 500,张三的卡里开始有 1200,李四的卡里开始有 300,从理论上,借完后,张三的卡里有 200,李四的卡里应该有 1300。

    我们将 张三向李四同时进行的两次转账操作分别称为 T1 和 T2,在现实世界中 T1 和 T2 是应该没有关系的,可以先执行完 T1,再执行 T2,或者先执行完 T2,再执行 T1,结果都是一样的。但是很不幸,真实的数据库中 T1 和 T2 的操作可能交替执行的,执行顺序就有可能是:

    如果按照上图中的执行顺序来进行两次转账的话,最终我们看到,张三 的账户里还剩 700 元钱,相当于只扣了 500 元钱,但是李四的账户里却成了 1300 元钱,多出现了 500 元,银行是不是亏了!

    所以对于现实世界中状态转换对应的某些数据库操作来说,不仅要保证这些 操作以原子性的方式执行完成,而且要保证其它的状态转换不会影响到本次状态转换,这个规则被称之为隔离性。

    MySQL InnoDB 引擎通过 锁机制、MVCC 等手段来保证事务的隔离性( 默认支持的隔离级别是 REPEATABLE-READ )。

    持久性(Durability)

    一旦事务提交,则其所做的修改就会永久保存到数据库中。此时即使系统崩溃,已经提交的修改数据也不会丢失。MySQL事务的持久性是通过redo log 来实现的。redo log也是InnoDB存储引擎特有的。具体实现方式是:当发生数据修改(增、删、改)的时候,InnoDB引擎会先将记录写到redo log中,并更新内存,此时更新就算完成了。同时InnoDB引擎会在合适的时机将记录刷到磁盘中。

    redo log是物理日志,记录的是在某个数据页做了什么修改,而不是SQL语句的形式。它有固定大小,是循环写的方式记录日志,空间用完后会覆盖之前的日志。

    undo log保证原子性,redo log保证持久性,设置隔离级别,保证并发事务进行的时候,保证数据一致性。

    # 事务并发引发的问题

    更新丢失(Lost Update)或脏写

    当两个或多个事务选择同一行,然后基于最初选定的值更新该行时,由于每个事务都不知道其他事务的存在,就会发生丢失更新问题–最后的更新覆盖了由其他事务所做的更新。

    脏读(Dirty Reads)

    事务A读取到了事务B已经修改但尚未提交的数据,还在这个数据基础上做了操作。此时,如果B事务回滚,A读取的数据无效,不符合一致性要求

    不可重复读 (Non-Repeatable Reads)

    事务 A 多次读取同一数据,事务 B 在事务A多次读取的过程中,对数据作了更新并提交,导致事务A多次读取同一数据时,结果 不一致。事务A内部的相同查询语句在不同时刻读出的结果不一致,不符合隔离性

    幻读(Phantom Reads)

    一个事务按相同的查询条件重新读取以前检索过的数据,却发现其他事务插入了满足其查询条件的新数据,这种现象就称为“幻读”。

    一句话:事务A读取到了事务B提交的新增数据,不符合隔离性

    # SQL标准中的四种隔离级别

    “脏读”、“不可重复读”和“幻读”,其实都是数据库读一致性问题,必须由数据库提供一定的事务隔离机制来解决。

    READ UNCOMMITTED:未提交读。

    READ COMMITTED:已提交读。

    REPEATABLE READ:可重复读。

    SERIALIZABLE:可串行化

    SQL 标准中规定,针对不同的隔离级别,并发事务可以发生不同严重程度的问题,具体情况如下:

    也就是说:

    READ UNCOMMITTED 隔离级别下,可能发生脏读、不可重复读和幻读问题。

    READ COMMITTED 隔离级别下,可能发生不可重复读和幻读问题,但是不可以发生脏读问题。

    REPEATABLE READ 隔离级别下,可能发生幻读问题,但是不可以发生脏读和不可重复读的问题。

    SERIALIZABLE 隔离级别下,各种问题都不可以发生。

    数据库的事务隔离越严格,并发副作用越小,但付出的代价也就越大,因为事务隔离实质上就是使事务在一定程度上“串行化”进行,这显然与“并发”是矛盾的。

    同时,不同的应用对读一致性和事务隔离程度的要求也是不同的,比如许多应用对“不可重复读"和“幻读”并不敏感,可能更关心数据并发访问的能力。

    常看当前数据库的事务隔离级别: show variables like 'tx_isolation';

    Mysql默认的事务隔离级别是可重复读

    准备一张表

    CREATE TABLE `account` (
    `id`  int NOT NULL AUTO_INCREMENT ,
    `name`  varchar(255) NULL ,
    `balance`  int NULL ,
    PRIMARY KEY (`id`)
    )
    ;
    INSERT INTO`account` (`name`, `balance`) VALUES ('刘备', '450');
    INSERT INTO`account` (`name`, `balance`) VALUES ('张飞', '16000');
    INSERT INTO `account` (`name`, `balance`) VALUES ('关羽', '2400');
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10

    # 未提交读(READ UNCOMMITED)

    事务A读取到事务B未提交的数据

    事务A读取了事务B更新的数据,然后B回滚操作,那么A读取到的数据是脏数据

    设置事务隔离级别

    set SESSION TRANSACTION ISOLATION LEVEL READ UNCOMMITTED;
    
    1

    事务A:

    image-20211212211517759

    在客户端A的事务提交之前,打开另一个客户端B,更新表account:

    image-20211212211335245

    虽然客户端B的事务还没提交,但是客户端A就可以查询到B已经更新的数据:

    image-20211212211431966

    一旦客户端B的事务因为某种原因回滚,所有的操作都将会被撤销,那客户端A查询到的数据其实就是脏数据.

    # 已提交读(READ COMMITED)

    set SESSION TRANSACTION ISOLATION LEVEL read committed;
    
    1

    可以读到已经事务提交的数据,不能出现脏读

    客户端A:

    image-20211212211845738

    在客户端A的事务提交之前,打开另一个客户端B,更新表account:

    image-20211212212016311

    客户端B的事务还没提交,客户端A不能查询到B已经更新的数据,解决了脏读问题

    客户端B的事务提交

    image-20211212212324916

    客户端A能查到最新的数据,产生了不可重复读。

    image-20211212212534966

    # 可重复读(REPEATABLE READ)

    set SESSION TRANSACTION ISOLATION LEVEL repeatable read;
    
    1

    在同一个事务中读到是同一条数据,其他事务修改了读的也是修改前的数据

    不能出现脏读和不可重复读

    特别注意的是MySQL数据库在RR隔离级别时候也解决了幻读问题

    客户端A:

    image-20211212212752659

    在客户端A的事务提交之前,打开另一个客户端B,更新表account并提交

    image-20211212213046799

    在客户端A查询表account的所有记录,两次查询结果一样,解决了不可重复读

    image-20211212213153084

    在客户端B,插入一条新数据后提交

    在客户端A查询表account的所有记录,没有查出新增数据,所以没有出现幻读

    # 可串行化

    set SESSION TRANSACTION ISOLATION LEVEL serializable;
    
    1

    在一个事务未提交时候,另外一个事务不能对这个表的数据修改,包括新增、修改、删除

    客户端A:

    打开一个客户端B,并设置当前事务模式为serializable,更新相同的id为1的记录会被阻塞等待,更新id为2的记录可以成功,说明在串行模式下innodb的查询也会被加上行锁。

    如果客户端A执行的是一个范围查询,那么该范围内的所有行包括每行记录所在的间隙区间范围(就算该行数据还未被插入也会加锁,这种是间隙锁)都会被加锁。此时如果客户端B在该范围内插入数据都会被阻塞,所以就避免了幻读。

    这种隔离级别并发性极低,开发中很少会用到。

    上次更新: 2024/03/11, 15:54:57
    MVCC
    「数据库、数据库连接池、数据源」这些概念你真的理解了吗?

    ← MVCC 「数据库、数据库连接池、数据源」这些概念你真的理解了吗?→

    最近更新
    01
    一个注解,优雅的实现接口幂等性
    11-17
    02
    MySQL事务(超详细!!!)
    10-14
    03
    阿里二面:Kafka中如何保证消息的顺序性?这周被问到两次了
    10-09
    更多文章>
    Theme by Vdoing | Copyright © 2024-2024

        辽ICP备2023001503号-2

    • 跟随系统
    • 浅色模式
    • 深色模式
    • 阅读模式