MySQL的事务隔离级别

什么叫事务

事务就是一组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;
4424012-f8787187bfbfbdc9.png
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;
4424012-02b87b9d0a1bcb8a.png
image.png

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


4424012-8146fb24bc8b68ad.png
image.png

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


4424012-3e803e3a0a3422a9.png
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。要想解决这个问题可以采用读已提交的隔离级别
4424012-9287d6f4a17393dc.png
image.png
  • 不可重复读(read-committed)

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

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

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

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


4424012-127b0a9354bf0081.png
image.png

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


4424012-e79e3464d7c60e3c.png
image.png

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

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

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

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

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


4424012-dbd5d49dc9c3b943.png
image.png

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


4424012-eea4ba1cd524663a.png
image.png

④事务A更新一条数据然后查看,会发现数据跟想象的不一样,age的数据是根据事务B的结果进行计算的。数据的一致性倒是没有被破坏。可重复读的隔离级别下使用了MVCC机制,select操作不会更新版本号,是快照读(历史版本);insert、update和delete会更新版本号,是当前读(当前版本)。
4424012-396a8e09682617d5.png
image.png

⑤当事务B重新开启事务添加一条信息的话会出现事务锁,事务A还是之前数据。没有出现幻读。
4424012-e7d50c314b3a7efc.png
image.png

4424012-b81ea4deca627c1f.png
image.png
  • 串行化(serializable)

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


4424012-3a067e12b226e904.png
image.png

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


4424012-dbb54ddef62c0eb3.png
image.png

重要

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

级别顺序(由低到高)

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值