Mysql事务隔离级别

事务定义

事务是指多条DML(insert, delete, update)语句操作要么全部执行成功,要么全部执行失败,不存在一部分语句执行成功,一部分失败的现象。我们把这些操作理解为是不可分割的最小操作单元。

事务特性

  1. 原子性:Atomicity,操作要么全部成功,要么全部失败。
  2. 一致性: Consistency,事务执行前后数据必须保持一致,比如A转给B一百元钱,不能出现A的钱减少,B的钱不增加问题。
  3. 隔离性: Isolation,一个事务的操作结果对另外一个事务的可见性,具体看下文的隔离级别。
  4. 持久性: Durability,事务执行成功后,它的改变是永久性的,不会因为主机重启导致数据丢失。

隔离级别

  1. 读未提交
  2. 读已提交
  3. 可重复读
  4. 序列化

数据库并发访问带来的问题

  1. 脏读:事务A读取事务B未提交的数据,由于某些原因事务B进行了回滚操作,导致事务A读取的数据是不正确的。
  2. 不可重复读:两事务A第一次读取某条数据值是'hello',此时事务B进该条数据进行修改,修改为'world'并提交,此时事务A又去读这条数据,发现和第一次读取的值不一致。
  3. 幻读:事务A第一次查询tb_user里的数据行数是4,此时事务B向tb_user里插入了一条数据并提交事务,此时事务A又去查询tb_user表里的数据行数,发现和第一次返回的值不一样
    注意: 看着不可重复读和幻读意思差不多,其实两者是有区别的,不可重复读侧重的是修改数据,而幻读侧重是新增和删除数据

事务命令

  1. 开启事务:begin 或者 start transaction
  2. 提交事务:commit
  3. 事务回滚:rollback
  4. 修改事务隔离级别
    session: set [session | global] transaction level [read uncommited | read committed | repeatable read | serializable]

隔离级别示例

注意:在操作前先把自动提交关闭: set autocommit=false
注意:以下例子图中的操作必须按照 1,2,3来依次操作
注意:以下例子的email.tb_user 是指 email数据库的tb_user表

读未提交

  1. 打开客户端A和B, 设置事务隔离级别为读未提交,然后分别开启事务。

  2. 客户端A先执行查看数据,客户端B更新数据,然后客户端A再查询数据,发现客户端A可以看到客户端B未提交的数据。

  3. 由于未知原因导致客户端B事务回滚,此时客户端A读取到的数据和上次读取的结果不一致,也就是脏读。

为了解决脏读的问题,我们把事务的隔离级别调整为读已提交。

读已提交

  1. 打开客户端A和B, 设置事务隔离级别为读已提交,然后分别开启事务。

  2. 客户端A先执行查看数据,客户端B更新数据,然后客户端A再查询数据,发现客户端A看不到了客户端B未提交的数据。

  3. 此时客户端B提交事务,客户端A再查询数据,发现客户端A可看到客户端B已提交的数据。

  4. 客户端A第一次读取的数据和第二次读取的数据不一致,存在不可重复读的问题。

为了解决脏读的问题,我们把事务隔离级别调整为读已提交,但依然存在不可重复读的问题,现在把事务隔离级别调整为可重复读。

可重复读

  1. 打开客户端A和B, 设置事务隔离级别为可重复读,然后分别开启事务。

  2. 客户端A先执行查看数据,客户端B更新数据,然后客户端A再查询数据,发现客户端A看不到了客户端B未提交的数据。

  3. 此时客户端B提交事务,客户端A再查询数据,发现客户端A不可看到客户端B已提交的数据。

  4. 隔离级别是可重复读的时候,看着已经解决了所有问题,但这是假象,看如下操作,以下是一个总图,有多个操作;

上图大致流程是这样的,客户端A和客户端B分别设置隔离级别为可重复读,然后开启事务,客户端A执行依次查询操作获取到5条数据,然后客户端B执行新增数据操作并提交事务,然后客户端A执行修改全部表数据操作,并查询数据,发现查询到6条数据,莫名其妙的比上次查询多了一条,感觉像是幻觉,这中现象称为幻读。为了解决幻读问题,我们可以把事务隔离级别调整为串行化。

既然串行化可解决 脏读、不可重复、幻读的问题,那是不是直接把隔离级别设置为串行化就万事大吉了呢,然后并不是,隔离级别设置越高,会导致数据库的并行度降低,执行效率不高,具体设置什么隔离级别,根据需求决定,毕竟存在即合理嘛

原文地址:https://www.cnblogs.com/rookie-test/p/12591138.html