tulip notes
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

Star-Lord

希望一天成为大师的学徒
首页
  • 学习笔记

    • 《Vue》
  • 踩坑日记

    • JavaScript
  • MQ
  • Nginx
  • IdentityServer
  • Redis
  • Linux
  • Java
  • SpringBoot
  • SpringCloud
  • MySql
  • docker
  • 算法与设计模式
  • 踩坑与提升
  • Git
  • GitHub技巧
  • Mac
  • 网络
  • 项目构建合集
  • 一些技巧
  • 面试
  • 一些杂货
  • 友情链接
  • 项目发布
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • 设计相关

  • 运行相关

  • 事务相关

    • MySql的事务4个隔离级别
      • 4个隔离级别
        • READ UNCOMMITTED——读未提交
        • READ COMMITTED——读已提交
        • REPEATABLE READ——可重复读
        • SERIALIZABLE——序列化
        • 默认级别
      • 相关操作
      • 解决的问题
        • 脏读
        • 不可重复读
        • 幻读
      • 隔离的实现原理
  • 表设计实战系列

  • 分库分表

  • 框架使用

  • 常用sql跟关键字

  • 安装与卸载相关

  • 《MySql》笔记
  • 事务相关
EffectTang
2024-11-14
目录

MySql的事务4个隔离级别

# MySql的事务4个隔离级别

# 4个隔离级别

MySQL 中事务的隔离级别一共分为四种,分别如下:

  1. 未提交读(READ UNCOMMITTED)
  2. 提交已读(READ COMMITTED)
  3. 可重复读(REPEATABLE READ)
  4. 序列化(SERIALIZABLE)——隔离级别最高

从上往下,隔离级别越来越高,其中序列化是最高的,同时也是效率最低的。下面从最低的读未提交开始往上介绍,四种不同的隔离级别:

# READ UNCOMMITTED——读未提交

READ UNCOMMITTED 提供了事务之间最小限度的隔离。除了容易产生虚幻的读操作和不能重复的读操作外,处于这个隔离级的事务可以读到其他事务还没有提交的数据,如果这个事务使用其他事务不提交的变化作为计算的基础,然后那些未提交的变化被它们的父事务撤销,这就导致了大量的数据变化。

# READ COMMITTED——读已提交

READ COMMITTED 隔离级别的安全性比 REPEATABLE READ 隔离级别的安全性要差。处于 READ COMMITTED 级别的事务可以看到其他事务对数据的修改。也就是说,在事务处理期间,如果其他事务修改了相应的表,那么同一个事务的多个 SELECT 语句可能返回不同的结果。

# REPEATABLE READ——可重复读

在可重复读在这一隔离级别上,事务不会被看成是一个序列。不过,当前正在执行事务的变化仍然不能被外部看到,也就是说,如果用户在另外一个事务中执行同条 SELECT 语句数次,结果总是相同的。(因为正在执行的事务所产生的数据变化不能被外部看到)。

# SERIALIZABLE——序列化

如果隔离级别为序列化,则用户之间通过一个接一个顺序地执行当前的事务,这种隔离级别提供了事务之间最大限度的隔离。

# 默认级别

在 MySQL 数据库种,默认的事务隔离级别是 REPEATABLE READ,也就是RR。

那为什么默认是可重复读呢?

# 相关操作

# 解决的问题

为什么会有四种隔离级别呢?那必然是出于对不同的安全和性能来考虑的。隔离级别越高,它的安全性就越好,同时它的性能也越差。下面就一起来看看,这个四种级别各自解决了哪些问题。

# 脏读

一个事务读到另外一个事务还没有提交的数据,称之为脏读。

只有读未提交这种级别才存在脏读。而读已提交则解决了脏读,但未解决不可重复读。

# 不可重复读

和脏读的区别在于,脏读是看到了其他事务未提交的数据,而不可重复读是看到了其他事务已经提交的数据(由于当前 SQL 也是在事务中,因此有可能并不想看到其他事务已经提交的数据)。

以下是一个简单的例子:

# 默认为 100
START TRANSACTION;
UPDATE order set account=account+100 where id='01';
COMMIT;
# 事务B
1
2
3
4
5
START TRANSACTION;
SELECT * from account where id='01';
SELECT * from account where id='01';
COMMIT;
# 事务A
1
2
3
4
5

事务A,第一次查询时,事务B还未开始,此时查到值为100,在进行第二次查询之前,事务B开始启动并完成。当事务A第二次查询时,就会发现account值为200,这就是所谓的不可重复读。

而数据库的第三个级别——可重复读则是解决了这个问题,但它没解决幻读。

# 幻读

假设我们有一个表 orders,其中包含以下数据:

order_id customer_id amount
1 101 100
2 102 200
3 103 150

有两个事务 T1 和 T2,它们按以下步骤执行:

  1. 事务 T1 开始:
START TRANSACTION;
SELECT * FROM orders WHERE customer_id = 101;
1
2

结果:

| order_id | customer_id | amount |
|----------|-------------|--------|
| 1        | 101         | 100    |
1
2
3

事务 T2 插入一条新记录:

START TRANSACTION;
INSERT INTO orders (customer_id, amount) VALUES (101, 120);
COMMIT;
1
2
3

事务 T1 再次执行相同的查询:

SELECT * FROM orders WHERE customer_id = 101;
# 此时 你会惊奇的发现 结果有2条,似乎出现了 幻觉

#| order_id | customer_id | amount |
#|----------|-------------|--------|
#| 1        | 101         | 100    |
#| 4        | 101         | 120    |
1
2
3
4
5
6
7

你可能会说,它跟不可重复读好像啊,的确很像,不过你仔细查看就会发现,它们的区别。

事务T2,做的操作可不是更新,而是新增。同样的,如果事务T2删除了数据,T1再次查看的话,也发现,没有数据。此时级别为可重复读,为什么两次查询结果不一样呢。

接下来再来一个例子,它可能更接近幻读。

两个窗口 A 和 B,将 B 窗口的隔离级别改为 READ COMMITTED,

然后在 A 窗口输入如下测试 SQL:

START TRANSACTION;
insert into account(name,balance) values('zhangsan',1000);
COMMIT;
1
2
3

在 B 窗口输入如下测试 SQL:

START TRANSACTION;
SELECT * from account;
insert into account(name,balance) values('zhangsan',1000);
COMMIT;
1
2
3
4

测试方式如下:

  1. 首先执行 B 窗口的前两行 SQL,开启事务并查询数据,此时查到的只有 javaboy 和 itboyhub 两个用户。
  2. 执行 A 窗口的前两行 SQL,插入一条记录,但是并不提交事务。
  3. 执行 B 窗口的第二行 SQL,由于现在已经没有了脏读问题,所以此时查不到 A 窗口中添加的数据。
  4. 执行 B 窗口的第三行 SQL,由于 name 字段唯一,因此这里会无法插入。此时就产生幻觉了,明明没有 zhangsan 这个用户,却无法插入 zhangsan。

总结:某些锁只锁现在有的数据,对于新增的数据,或者删除的数据,是无法锁住的。这就是所谓的幻读,而可重复度只解决了已存在数据的问题。

# 隔离的实现原理

Mvcc +cas,mvcc也是一种乐观锁的实现

多版本控制,待补充

数据快照,保存着 更新前后的所有数据

每条数据都有额外的隐藏列,

  • 事务id
  • DB_Roll_PTR -数据指针

间隙锁?

上次更新: 2025/04/23, 16:23:16
几种count的性能比较
表设计实战-自增、资金与字符

← 几种count的性能比较 表设计实战-自增、资金与字符→

最近更新
01
面向切面跟自定义注解的结合
05-22
02
时间跟其他数据的序列化
05-19
03
数据加密与安全
05-17
更多文章>
Theme by Vdoing | Copyright © 2023-2025 EffectTang
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式