美文网首页MySQL
MySQL的事务隔离级别

MySQL的事务隔离级别

作者: 这真的是一个帅气的名字 | 来源:发表于2019-08-21 00:13 被阅读4次

    什么叫事务

    事务就是一组sql组成的操作单元,要么操作全部成功,要么全部失败。

    事务的基本要素(ACID)(四个)

    • 原子性

    一个事务必须被视为一个不可分割的最小工作单元,整个事务要么全部成功,要么失败全部回滚。事务中不能只执行其中的一部分操作。

    • 一致性

    数据库总是从一个一致的状态转换到另外一个一致的状态。比如两个update,第一个update之后系统崩溃了,也不会对数据有影响,因为事务还没有提交。

    • 隔离性

    一个事务所做的修改,在提交之前,对其他事务应该是不可见的。

    • 持久性

    一旦事务提交,那么所做的修改就会永久的保存到数据库中。

    事务的并发问题(三种)

    脏读

    事务B读取了事务A未提交的修改数据

    不可重复读

    事务A一直查询,事务B在事务A查询的期间对数据做了更新,导致事务A读取的结果不一致

    幻读

    事务A对摸个数据范围记录时,事务B在事务A查询的范围内插入了新的记录。当事务A再次读取事务时,会发现新增的记录,就想出现幻觉似的。

    事务的隔离级别(四种)

    • 读未提交(read-uncommitted)

    允许脏读,也就是可能读取到其他会话中未提交事务修改的数据

    例子:
    ①事务A命令行设置事务模式为read uncommitted(未提交读),查询表member的初始状态:

     set session transaction isolation level read uncommitted;
     start transaction;
     select * from member;
    
    image.png

    ②事务A到此暂停,打开事务B,让事务B更新一条数据

     set session transaction isolation level read uncommitted;
     start transaction;
     update member set age = age-10 where name = 'zhangsan';
    select * from member;
    
    image.png

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


    image.png

    ④事务B如果回滚,所有的操作都将会被撤销,那事务A查询到的数据其实就是脏数据:


    image.png
    ⑤如果事务A执行更新语句update member set age = age -3 where name='zhangsan';,zhangsan的age没有变成0,居然是10,What???3-3=10???,这样子算其实是因为事务A不知道事务B回滚了.所以会用3-3=0.其实程序是13-3=10。要想解决这个问题可以采用读已提交的隔离级别
    image.png
    • 不可重复读(read-committed)

    只能读取到已经提交的数据。Oracle等多数数据库默认都是该级别 (不重复读)

    ①把事务A的事务模式设置成read committed(未提交读),查询表member的所有记录:

     set session transaction isolation level read committed;
     start transaction;
    
    image.png

    ②打开事务B,更新一条数据


    image.png

    ③事务A再查询,查不到事务B的修改,解决了脏读


    image.png
    ④事务B提交事务,事务A再查询,结果不一致,即产生了不可重复读的问题
    image.png
    • 可重复读(repeatable-read)

    可重复读。在同一个事务内的查询都是事务开始时刻一致的,InnoDB默认级别。在SQL标准中,该隔离级别消除了不可重复读,但是还存在幻象读

    ①打开事务A并设置当前事务模式为repeatable read,查询表member的所有记录

     set session transaction isolation level repeatable read;
    start transaction;
    select * from member;
    
    image.png

    ②事务A提交之前打开事务B更新一条并且提交事务


    image.png

    ③事务A再次查询,发现此时的信息是一致的,没有出现不可重复读的问题


    image.png
    ④事务A更新一条数据然后查看,会发现数据跟想象的不一样,age的数据是根据事务B的结果进行计算的。数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
    image.png
    ⑤当事务B重新开启事务添加一条信息的话会出现事务锁,事务A还是之前数据。没有出现幻读。
    image.png
    image.png
    • 串行化(serializable)

    完全串行化的读,每次读都需要获得表级共享锁,读写相互都会阻塞
    ①打开事务A,并设置当前事务模式为serializable,查询表member的初始值:


    image.png

    ②打开事务B,插入一条数据,会报错。mysql中事务隔离级别为serializable时会锁表,因此不会出现幻读的情况,这种隔离级别并发性极低,开发中很少会用到。


    image.png

    重要

    ①事务隔离级别为读提交时,写数据只会锁住相应的行
    ②事务隔离级别为可重复读时,如果检索条件有索引(包括主键索引)的时候,默认加锁方式 是next-key锁,如果检索条件没有索引,更新数据时候会锁住整张表。一个间隙被事务加了锁,其他事物是不能再这个间隙插入记录的,这样可以防止幻读。
    ③事务隔离级别为串行化时,读写数据都回锁住整张表
    ④隔离级别越高,越能保证数据的完整性和一致性,但是对并发性能的影响也就越大。
    mysql的mvcc机制
    next-key锁

    级别顺序(由低到高)

    Read uncommitted (读未提交)、Read committed(读提交/不可重复读) 、Repeatable read(可重复读) 、Serializable (串行化)

    相关文章

      网友评论

        本文标题:MySQL的事务隔离级别

        本文链接:https://www.haomeiwen.com/subject/nlbmsctx.html