首页
技术小册
AIGC
面试刷题
技术文章
MAGENTO
云计算
视频课程
源码下载
PDF书籍
「涨薪秘籍」
登录
注册
01 | 基础架构:一条SQL查询语句是如何执行的?
02 | 日志系统:一条SQL更新语句是如何执行的?
03 | 事务隔离:为什么你改了我还看不见?
04 | 深入浅出索引(上)
05 | 深入浅出索引(下)
06 | 全局锁和表锁 :给表加个字段怎么有这么多阻碍?
07 | 行锁功过:怎么减少行锁对性能的影响?
08 | 事务到底是隔离的还是不隔离的?
09 | 普通索引和唯一索引,应该怎么选择?
10 | MySQL为什么有时候会选错索引?
11 | 怎么给字符串字段加索引?
12 | 为什么我的MySQL会“抖”一下?
13 | 为什么表数据删掉一半,表文件大小不变?
14 | count(*)这么慢,我该怎么办?
15 | 答疑文章(一):日志和索引相关问题
16 | “order by”是怎么工作的?
17 | 如何正确地显示随机消息?
18 | 为什么这些SQL语句逻辑相同,性能却差异巨大?
19 | 为什么我只查一行的语句,也执行这么慢?
20 | 幻读是什么,幻读有什么问题?
21 | 为什么我只改一行的语句,锁这么多?
22 | MySQL有哪些“饮鸩止渴”提高性能的方法?
23 | MySQL是怎么保证数据不丢的?
24 | MySQL是怎么保证主备一致的?
25 | MySQL是怎么保证高可用的?
26 | 备库为什么会延迟好几个小时?
27 | 主库出问题了,从库怎么办?
28 | 读写分离有哪些坑?
29 | 如何判断一个数据库是不是出问题了?
30 | 答疑文章(二):用动态的观点看加锁
31 | 误删数据后除了跑路,还能怎么办?
32 | 为什么还有kill不掉的语句?
33 | 我查这么多数据,会不会把数据库内存打爆?
34 | 到底可不可以使用join?
35 | join语句怎么优化?
36 | 为什么临时表可以重名?
37 | 什么时候会使用内部临时表?
38 | 都说InnoDB好,那还要不要使用Memory引擎?
39 | 自增主键为什么不是连续的?
40 | insert语句的锁为什么这么多?
41 | 怎么最快地复制一张表?
42 | grant之后要跟着flush privileges吗?
43 | 要不要使用分区表?
44 | 答疑文章(三):说一说这些好问题
45 | 自增id用完怎么办?
当前位置:
首页>>
技术小册>>
MySQL 实战 45 讲
小册名称:MySQL 实战 45 讲
### 03 | 事务隔离:为什么你改了我还看不见? 在数据库管理系统中,事务(Transaction)是一个不可分割的工作单位,它确保了一组数据库操作要么全部执行成功,要么在遇到错误时全部撤销,以保持数据的一致性和完整性。然而,在多用户并发访问数据库的场景下,事务之间的相互影响可能会引发一系列问题,如脏读(Dirty Read)、不可重复读(Non-Repeatable Read)和幻读(Phantom Read)。为了解决这些问题,数据库系统引入了事务隔离级别(Transaction Isolation Levels)的概念。本章将深入探讨事务隔离的概念、重要性以及MySQL中支持的四种隔离级别,并解释为什么在某些情况下,“你改了我还看不见”的现象会发生。 #### 一、事务隔离的基本概念 事务隔离性是数据库事务处理中的一项重要特性,它要求事务在并发执行时,系统能保证一个事务内部的操作对其他并发执行的事务是隔离的,即一个事务的执行不能被其他事务干扰。事务的隔离性是通过锁(Locks)和事务日志(Transaction Logs)等机制来实现的,但直接操作这些底层机制对于大多数开发者来说并不直观,因此,数据库管理系统提供了不同级别的事务隔离设置,允许开发者根据应用的需求选择合适的事务隔离级别。 #### 二、事务隔离级别 SQL标准定义了四种事务隔离级别,从低到高依次为: 1. **读未提交(Read Uncommitted)** - 在这个级别下,一个事务可以读取到另一个事务未提交的数据。这会导致脏读现象,即一个事务读取了另一个事务未提交的数据,而这些数据在后续操作中可能会被回滚,从而导致读取的数据无效。 2. **读已提交(Read Committed)** - 这也是大多数数据库系统的默认隔离级别。在这个级别下,一个事务只能读取到另一个事务已经提交的数据,避免了脏读的发生。但是,它仍然可能遇到不可重复读的问题,即在同一事务内,多次读取同一数据集合时,由于其他事务的插入、更新或删除操作,导致两次读取的结果不一致。 3. **可重复读(Repeatable Read)** - MySQL的默认事务隔离级别(在InnoDB存储引擎下)。在这个级别下,保证了在同一个事务中多次读取同样记录的结果是一致的,即避免了不可重复读的问题。但是,它仍然可能遇到幻读的问题,即当某个事务在读取某个范围内的记录时,另一个事务又在该范围内插入了新的记录,当之前的事务再次读取这个范围时,会发现有“幻影”般的记录出现。 4. **串行化(Serializable)** - 这是最高的隔离级别,它通过强制事务串行执行,来避免脏读、不可重复读和幻读。但是,这种级别的性能开销最大,因为它会极大地限制并发性。 #### 三、为什么“你改了我还看不见”? 理解了上述的事务隔离级别后,我们就可以解释为什么在某些情况下会出现“你改了我还看不见”的现象了。这主要涉及到不同隔离级别下,事务对数据的可见性规则。 - **在读未提交(Read Uncommitted)级别下**,理论上讲,如果一个事务修改了数据但尚未提交,另一个事务是可以读取到这些未提交的数据的。然而,在实际情况中,由于系统实现或性能考虑,数据库管理系统可能并不会立即将这些未提交的数据变化展现给其他事务,但这并不违反读未提交级别的定义。不过,这种情况与“你改了我还看不见”的直接现象关联不大,因为它更多关联于数据是否“脏”的问题。 - **在读已提交(Read Committed)级别下**,一个事务只能看到其他事务已经提交的数据变化。如果事务A修改了某条数据并提交,而事务B在事务A提交后才开始读取该数据,那么事务B将能看到事务A所做的修改。但如果事务B在事务A提交之前就尝试读取该数据,那么它将看不到事务A所做的修改,这在一定程度上可以解释“你改了我还看不见”的现象,但更准确地说是“你未提交我就看不见”。 - **在可重复读(Repeatable Read)级别下**,这是MySQL的默认隔离级别,它确保了在同一事务内多次读取相同记录的结果是一致的。如果事务A在事务B开始之前修改了某条数据并提交,事务B在读取该数据时,虽然能看到事务A的修改结果,但在事务B内部,如果它多次读取同一条数据,每次读取的结果都将保持一致,即使其他事务(如事务C)在此期间对该数据进行了修改并提交。这解释了为什么在可重复读级别下,即使数据被其他事务修改了,当前事务也可能“看不见”这些修改,因为它会保持第一次读取时的数据快照。 - **在串行化(Serializable)级别下**,由于事务被强制串行执行,理论上不会出现“你改了我还看不见”的情况,因为每个事务都会完整地看到其他事务的结果后再执行。但是,这种级别的性能开销使得它在实际应用中很少被采用。 #### 四、实践中的选择与优化 在选择事务隔离级别时,开发者需要权衡数据的一致性需求与系统性能之间的平衡。过高的隔离级别虽然能保证数据的高度一致性,但可能会显著降低系统的并发处理能力;而过低的隔离级别虽然能提高性能,但可能无法满足应用对数据一致性的要求。 在MySQL中,可以通过设置全局或会话级别的`transaction_isolation`变量来更改事务的隔离级别。例如,将当前会话的事务隔离级别设置为可重复读(MySQL的默认级别): ```sql SET SESSION transaction_isolation = 'REPEATABLE-READ'; ``` 此外,开发者还可以通过合理的索引设计、优化查询语句、使用锁定提示(尽管MySQL的InnoDB引擎主要依赖自动锁定机制)等方式来减少对事务隔离级别的依赖,提高系统的整体性能和一致性。 #### 五、总结 事务隔离性是数据库事务处理中的一个重要特性,它确保了事务在执行过程中的数据一致性和完整性。通过理解并合理设置事务隔离级别,开发者可以在保证数据一致性的同时,优化系统的并发处理能力。MySQL提供了四种事务隔离级别,每种级别都有其适用场景和潜在问题。在实践中,开发者应根据应用的具体需求选择合适的隔离级别,并通过其他技术手段来进一步提升系统的性能和一致性。
上一篇:
02 | 日志系统:一条SQL更新语句是如何执行的?
下一篇:
04 | 深入浅出索引(上)
该分类下的相关小册推荐:
MySQL从入门到精通(三)
细说MySQL(零基础到高级应用)
MySQL从入门到精通(五)
MySQL从入门到精通(一)
MySQL必会核心问题
MySQL从入门到精通(二)
MySQL8.0入门与实践
SQL零基础到熟练应用(增删改查)
MySQL从入门到精通(四)