数据库的事务的并发问题和四种隔离级别

本文详细阐述了MySQL中并发问题的表现形式,如脏写、脏读、不可重复读和幻读,并介绍了SQL的四种隔离级别及其在解决这些问题上的作用。脏写是最严重的,而SERIALIZABLE隔离级别虽然能解决所有并发问题但性能低。
摘要由CSDN通过智能技术生成

1. 数据并发问题

MySQL是一个客户端/服务器架构的软件,可以有若干个客户端与之连接,连接上之后,就可以称之为一个会话(Session),对于服务器来说可能同时处理多个Session,也就是对服务器来说可能同时处理多个事务。但是由于事务的隔离性,理论上如果多个事务有对同一个表中的数据进行的操作,他们的执行顺序应该按照事务到达的顺序进行排队(也叫序列化),但是这样对性能影响太大,比如SessionA,SessionB,SessionC都提交了一个事务,事务到达的顺序为A -> C -> B

Untitled Diagram.drawio-4.png

对比上面的图片我们发现虽然序列化可以满足事务的隔离性问题,但是对性能影响太大,难道就没有什么两全其美的方法吗?在解决问题之前,我们得先明白同时处理多个Session时可能会出现一系列并发问题,具体总结为以下几种:

  • 脏写
  • 脏读
  • 不可重复读
  • 幻读

创建一个表tb_student,数据如下:
image.png

下面我将根据该表数据进行通过举例+说明的方式进行解释。

1.1 脏写(Dirty Write)

脏写示意图:

执行次序Session ASession B
1事务开始
2事务开始
3UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 1
4UPDATE tb_student SET name = ‘wangwu’ WHERE stu_id = 1
5事务提交
6事务回滚
  • 前提事件: Session A和Session B各自开启了一个事务,并且他们都修改了同一个表的同一个字段

  • 附加事件: Session A在将"zhangsan"修改为"wangwu"后并提交事务,Session B却回滚了事务

  • 导致结果: 本该成功修改的"wangwu"又变回了"zhangsan",由于SessionA修改了一个未提交的数据,导致SessionA修改数据失败,这就是脏写问题。

1.2 脏读(Dirty Read)

脏读示意图:

执行次序Session ASession B
1事务开始
2事务开始
3UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 1
4SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“lisi”)
5事务提交
6事务回滚
  • 前提事件: Session A和Session B各自开启了一个事务,Session A查询数据,Session B更改数据,它们的操作都是针对同一个表的。

  • 附加事件: 并且Session A在查询数据之前,Session B对数据进行了修改。此时Session A 读到的数据name值为"lisi",但是由于Session B 回滚事务。

  • 导致结果: name的实际值变又回了"zhangsan",此时Session A读到了一个未提交"脏数据",这就是脏读。

1.3 不可重复读(NON-REPEATED READ)

不可重复读示意图:

执行次序Session ASession B
1事务开始
2事务开始
3SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“zhangsan”)
4UPDATE tb_student SET name = ‘lisi’ WHERE stu_id = 1
5事务提交
6SELECT * FROM tb_student WHERE stu_id = 1;(此时name=“lisi”)
7事务提交

前提事件: Session A和Session B各自开启了一个事务,Session A查询数据, Session B更改数据,它们的操作都是针对同一个表

附加事件: Session A的事务中进行了两次(或多次)查询,在两次查询之间,Session B中的事务对表中的数据进行了修改

导致结果: 两次(或多次)查询的结果不一样,这就是不可重复读问题

1.4 幻读(Phantom)

幻读示意图:

执行次序Session ASession B
1事务开始
2事务开始
3SELECT * FROM tb_student(此时只读到一条数据)
4INSERT INTO tb_student VALUES(2,‘lisi’,‘男’,19)
5事务提交
6SELECT * FROM tb_student;(此时读到了两条数据)
7事务提交

前提条件: Session A和Session B各自开启了一个事务,Session A查询多条数据, Session B插入新数据,它们的操作都是针对同一个表的

附加条件: Session A的事务中进行了两次(或多次)查询,在两次查询之间,Session B中的事务在表中新增数据

导致结果: SessionA再次读取同一个表,读到了先前没读到的记录,就像产生了幻觉,这就是幻读问题

2. 四种隔离级别

前面所提到的并发问题亦有轻重之分:脏写 > 脏读 > 不可重复读 > 幻读

我们可以为了提高性能,根据业务的需要进行一定的取舍,这时就需要通过设置隔离级别来实现了,接下来我来为大家介绍一下SQL中的四种隔离级别,以及分别解决了前面提到的哪些并发问题。

注意:由于脏写问题太过恶劣,数据库不允许这种行为,因此所有的隔离级别都是在解决脏写问题的前提下谈的

SQL标准中设立了下面4种隔离级别(级别从低到高):

  • READ UNCOMMITTED:读未提交,在该隔离级别,所有事务都可以看到其他未提交事务的执行结果。不能避免脏读、不可重复读、幻读。

  • READ COMMITED:读已提交:它满足了隔离的简单定义:一个事务只能看见已提交事务所做的改变。这是绝大多数数据库系统的隔离级别(MySQL不是)。可以避免脏读

  • REPEATABLE READ:可重复读,如果事务B对表中的数据进行了修改并提交,那么事务A多次读到的数据内容都相同。可以避免脏读、不可重复读,这也是MySQL中的默认隔离级别。

    image.png

  • SERIALIZABLE:可序列化,确保事务可以从一个表中读取相同的行。在这个事务持续期间,禁止其他事务对该表进行任何操作。解决了所有并发问题,但是性能十分低下。
    可总结为下面的表格:

隔离级别解决脏读解决不可重复读解决幻读
READ UNCOMMITTEDNONONO
READ COMMITEDYESNONO
REPEATABLE READYESYESNO
SERIALIZABLEYESYESYES
  • 29
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

干脆面la

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值