MySQL事务的特性与隔离级别

引子

最近准备学习一下MySQL相关的知识。学习知识最好的方式就是去看官方文档。这里,我将根据官方文档的描述,总结一下MySQL事务的四大特性——ACID,以及MySQL数据库提供的四种隔离级别。

本文主要是翻译、整理自MySQL 8.0 的官方文档,各位朋友有兴趣的建议直接去官方文档查阅!

MySQL事务的特性

对于一个数据系统来说,必须满足ACID四大特性,这些特性都与事务紧密相关。MySQL的 InnoDB 引擎的事务功能遵循ACID原则。

原子性(Atomicity)

事务是一些可以被提交或回滚的工作单元。当一个事务对数据库进行多次更改时,要么所有更改在事务提交时成功,要么所有更改在事务回滚时撤消。

一致性(Consistency)

在每次提交或回滚之后,以及正在进行的事务处理期间,数据库始终保持一致状态。 如果跨多个表更新了相关数据,则查询要么得到所有旧值,要么得到所有新值,而不是新旧值的混合。

隔离性(Isolation)

事务在进行过程中是相互隔离的,它们不能相互干扰或查看彼此未提交的数据。这种隔离是通过锁机制实现的。用户在确保事务不会相互干扰的前提下,可以调整隔离级别,减少保护以提高性能和并发性。

持久性(Durability)

事务的结果是持久的:提交操作成功后,该事务所做的更改就不会受到一些外在原因的影响,比如电源故障,系统崩溃,竞争状况或许多非数据库应用程序容易受到的其他潜在危险。持久性通常涉及对磁盘存储的写操作,其中包含一定的额外操作,以防止在写操作期间出现电源故障或软件崩溃。在InnoDB中,双写缓冲区(doublewrite buffer)有助于提高持久性。

隔离级别

隔离级别是在多个事务同时进行更改和执行查询时,对性能与可靠性、一致性和结果再现性之间的平衡进行微调的设置。

InnoDB支持的隔离级别由高到低分别是:SERIALIZABLE、REPEATABLE READ、READ COMMITTED 和 READ UNCOMMITTED。InnoDB的表默认的隔离级别是REPEATABLE READ。关于这几种隔离级别,下面我会分别介绍。

SERIALIZABLE

这种隔离级别使用最保守的锁策略,以防止任何其他事务插入或更改由该事务读取的数据,直到该事务完成。这样,同一个查询可以在一个事务中反复运行,并确保每次都检索到相同的结果集。

这种隔离级别是SQL标准默认的隔离级别。

REPEATABLE READ

InnoDB的默认隔离级别。它可以防止被查询的任何行被其他事务更改,从而屏蔽“不可重复读”问题,但不会解决“幻读”问题。它使用适度严格的锁策略,以便一个事务中的所有查询都能看到来自同一快照的数据,即事务启动时的数据。

具有此隔离级别的事务执行UPDATE ... WHERE、DELETE ... WHERE、SELECT ... FOR UPDATE 和 LOCK IN SHARE MODE操作时,其他事务可能必须等待。

READ COMMITTED

这个隔离级别使用了一种稍微宽松的锁策略。这种锁策略为了提高性能,在事务之间放松了一些保护。此时事务不能看到来自其他事务的未提交数据,但可以看到当前事务启动后另一个事务提交的数据。因此,这个隔离级别的事务永远不会看到任何坏数据,但是它看到的数据可能在某种程度上取决于其他事务的执行时间。

当具有此隔离级别的事务执行 UPDATE ... WHERE 或 DELETE ... WHERE 操作时,其他事务可能必须等待。 该事务可以执行 SELECT ... FOR UPDATE和LOCK IN SHARE MODE 操作,而无需等待其他事务。

READ UNCOMMITTED

这种隔离级别在事务之间提供最少的保护。查询采用锁定策略,这种策略允许它们在通常需要等待另一个事务的情况下继续执行。然而,这种额外的性能是以不太可靠的结果为代价的,包括被其他事务更改但尚未提交的数据(称为脏读”)。要非常小心地使用这个隔离级别,并注意结果可能不一致或不可重复读,这取决于同时执行的其他事务。通常,具有此隔离级别的事务只执行查询,而不执行插入、更新或删除操作。

脏读、不可重复读 与 幻读

在上面我们提到了在MySQL事务中可能存在的一些问题,下面我们详细说一下。

脏读

脏读(dirty read)是指 一个事务在执行过程中,读取到由另一个事务更新但尚未提交的数据。

只有在隔离级别为“READ UNCOMMITTED”的情况下才可能出现“脏读”。

不可重复读

同一个事务中的多次查询,某一次查询后,数据被其他事务修改并提交,导致后续的查询返回了和前面不一样的结果。

比如,同一个事务中的两次相同的查询。第一次查询结果是 {"name":"张三","age":27}。第一次查询完成后,另一个事务修改了这一条记录,将张三的年龄修改为了35岁,导致第二次查询查到的结果是 {"name":"张三","age":35}。

在不同的隔离级别中,“SERIALIZABLE READ”和“REPEATABLE READ”两种级别解决了这个问题,

幻读

同一个事务中的多次查询,后面的查询结果中出现了前面的查询没有查到的结果。

比如,同一个事务中的两次相同的查询,查询条件是 WHERE name LIKE "%三%"。第一次查询结果是 {"name":"张三","age":27}。第一次查询完成后,另一个事务中的语句修改了 {"name":"李四","age":56} 这条记录,将李四的name修改成为了 “李三”。这就导致第二次查询的结果是 [{"name":"张三","age":27}, {"name":"李三","age":56}],出现了一条之前没有出现的结果{"name":"李三","age":56}。

“幻读”相对于“不可重复读”,要防备更加困难——因为 锁定第一次查询结果集中的所有行并不到阻止“幻读”的发生。只有“SERIALIZABLE READ”解决了“幻读”这个问题。

总结

终于总结完了,看完官方文档,深情气爽,这大概就是学习知识带给我的快乐吧~2020年开始,希望自己继续努力,年轻人,未来可期!!加油!

参考文档

1、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_acid

2、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_isolation_level

3、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_serializable

4、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_repeatable_read

5、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_read_committed

6、https://dev.mysql.com/doc/refman/8.0/en/glossary.html#glos_dirty_read

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值