MySQL 的可重复读怎么实现的?

MySQL的可重复读(Repeatable Read)是事务的隔离级别之一,它确保在一个事务中,多次读取同一数据的结果是一致的,即使有其他事务在并发修改数据。在可重复读隔离级别下,事务可以看到在事务开始前就已经存在的数据,并且在整个事务过程中,这些数据的可见性不会改变。

夏天了,都喜欢吃冰棍,就是那种通透的感觉,今天 V 哥的文章,也要让你感受一下,如何通透的理解这个问题:MySQL中可重复读的实现主要依赖于以下几个机制:

1. MVCC(多版本并发控制):

  • 在MySQL的InnoDB存储引擎中,MVCC通过保存数据的多个版本来实现。每个事务看到的是一致性视图中的数据快照,这个快照是在事务开始时创建的。
  • 当其他事务尝试修改数据时,它们会创建数据的新版本,而不是覆盖旧版本。这样,当前事务仍然可以看到它开始时的数据版本。

MVCC(多版本并发控制)是一种用于提高数据库系统并发性能的技术。它允许多个事务同时访问相同数据,而不会引起冲突,从而提高数据库的并发能力。以下是MVCC实现原理和机制的详细介绍:

1. 版本链(Version Chain)

在MVCC中,每行数据都可能有多个版本。这些版本通过一个版本链(也称为undo链)相互连接。每个版本包含了数据的快照,包括数据本身以及事务的元信息,如创建该版本的事务ID和时间戳。

2. Read View

当一个事务读取数据时,InnoDB会为该事务创建一个"Read View",它是一个数据的一致性快照。Read View包含了事务开始时所有已提交的数据版本,以及事务自己所做的修改。Read View确保了事务可以看到一致性的数据视图,即使其他事务在并发修改数据。

3. 一致性非锁定读取

事务读取数据时,不需要加锁,因为Read View会提供一个一致性的数据视图。这减少了锁的开销,提高了并发性能。

4. 写操作和Undo日志

当事务要修改数据时,InnoDB不会直接在当前数据上修改,而是通过Undo日志创建数据的一个新版本。这个新版本包含了修改前后的数据,以及事务的元信息。这样,其他事务仍然可以看到它们自己的Read View中的版本。

5. Gap Locks

为了维护数据的一致性,InnoDB在可重复读隔离级别下使用Gap Locks。Gap Locks锁定的是数据行之间的"间隙",而不是数据行本身。这可以防止其他事务在已锁定的间隙中插入新行,从而维护数据的一致性。

6. 版本链的清理

随着事务的提交或回滚,一些版本的数据不再被任何事务的Read View所需要。InnoDB会定期清理这些不再需要的版本,释放存储空间。这个清理过程称为"purge"。

7. 系统版本号(System Version Number, SVN)

每行数据都有一个系统版本号,用于标识该数据版本的创建时间。当事务尝试访问数据时,它会根据系统版本号和自己的Read View来确定应该读取哪个版本的数据。

MVCC的优缺点

优点:

  • 提高并发性能,减少锁的争用。
  • 允许非锁定读取,提高读取操作的性能。
  • 为事务提供一致性的数据视图。

缺点:

  • 增加存储开销,因为需要保存数据的多个版本。
  • 版本链的维护和清理可能增加系统负担。
  • 在高并发写入的场景下,可能引起写写冲突,导致事务回滚。

MVCC是现代数据库系统中实现高并发访问的关键技术之一,特别是在支持高并发读写操作的OLTP(在线事务处理)系统中。通过合理地使用MVCC,数据库可以提供更好的性能和一致性保证。

2. 行级锁定:

  • InnoDB使用行级锁定来控制对数据的并发访问。当一个事务读取一行数据时,InnoDB会给这行数据加上共享锁(shared lock)。
  • 如果另一个事务试图修改这行数据,它必须等待共享锁释放。这样,当前事务可以保证在事务期间看到的数据不会被其他事务修改。

行级锁定是数据库管理系统中用于实现事务隔离级别的一种锁定机制,它允许系统锁定数据表中的单行或多行记录,以保证事务的原子性、一致性、隔离性和持久性。以下是行级锁定的实现原理和机制的详细介绍:

1. 锁定粒度

行级锁定的粒度是数据库锁定机制中最小的,它只锁定事务操作的特定行,而不是整个表或页面。这允许多个事务并发访问同一个表中的不同行,从而提高并发性能。

2. 锁的类型

行级锁定通常包括两种类型的锁:

  • 共享锁(Shared Lock, S锁):当事务读取一行数据时,会在这行数据上加上共享锁。其他事务可以并发读取这行数据,但不能修改它。
  • 排它锁(Exclusive Lock, X锁):当事务需要修改一行数据时,会在这行数据上加上排它锁。这会阻止其他事务读取或修改这行数据,直到排它锁被释放。

3. 锁定机制

  • 锁定请求:当事务需要访问数据时,它会向数据库管理系统发送一个锁定请求。
  • 锁的授予:数据库管理系统会检查请求的行是否已经被其他事务锁定。如果没有,它会授予锁并记录锁的状态;如果有,事务可能需要等待锁被释放。
  • 锁的升级和降级:在某些情况下,事务可能需要将共享锁升级为排它锁,或者相反。这通常需要数据库管理系统进行额外的锁定管理。

4. 锁的兼容性

不同类型的锁之间存在兼容性规则,以确保事务的正确执行。例如:

  • 共享锁与其他共享锁是兼容的,但与排它锁不兼容。
  • 排它锁与其他类型的锁都不兼容。

5. 死锁检测

数据库管理系统会定期检测死锁情况,即两个或多个事务相互等待对方持有的锁。如果检测到死锁,系统会选择回滚其中一个或多个事务以解决死锁。

6. 锁的释放

事务完成后,无论是提交还是回滚,都会释放它持有的所有锁。这允许其他等待的事务继续执行。

7. 索引和锁定

行级锁定通常依赖于索引。如果事务通过索引查找数据,数据库管理系统可以直接锁定相应的行。如果没有索引,数据库可能需要扫描整个表来找到匹配的行,这会降低性能。

8. 锁定协议

数据库管理系统实现行级锁定时,会遵循一定的锁定协议,如两阶段锁定协议,以确保事务的隔离性和系统的稳定性。

MVCC与行级锁定

在支持MVCC的数据库系统中,行级锁定通常与MVCC结合使用。MVCC通过维护数据的多个版本来处理并发访问,而行级锁定则确保事务在修改数据时不会与其他事务冲突。

行级锁定是一种有效的并发控制机制,它通过锁定数据行而不是整个数据表,提高了数据库的并发处理能力。然而,行级锁定也带来了额外的管理开销,并且在高并发场景下可能导致锁竞争和死锁,需要数据库管理系统进行精细的锁定管理。

3. 间隙锁(Gap Locks):

  • 除了行级锁,InnoDB还会在可重复读隔离级别下使用间隙锁。间隙锁锁定的是一个范围,而不是具体的数据行。
  • 间隙锁可以防止其他事务在这个范围内插入新的数据,从而保证当前事务在事务期间看到的记录数不会改变。

间隙锁(Gap Lock)是数据库管理系统中用于处理并发控制的一种锁定机制,特别是在实现了多版本并发控制(MVCC)的数据库系统中,如MySQL的InnoDB存储引擎。间隙锁用于防止其他事务在已锁定的间隙中插入新行,从而维护数据的一致性和事务的隔离性。以下是间隙锁的实现原理和机制的详细介绍:

1. 间隙锁的定义

间隙锁锁定的是数据行之间的"间隙",而不是具体的数据行本身。它用于保护一个范围内的记录,但不锁定记录本身。

2. 间隙锁的类型

间隙锁主要有两种类型:

  • 共享间隙锁(Shared Gap Lock, SGAP):当一个事务需要读取一个范围的记录,但不锁定这些记录本身时,会使用共享间隙锁。
  • 排它间隙锁(Exclusive Gap Lock, XGAP):当一个事务需要在这个间隙中插入新记录时,会使用排它间隙锁。

3. 间隙锁的目的

间隙锁的主要目的是防止幻读(Phantom Reads)。幻读发生在一个事务在读取某个范围内的记录后,另一个事务插入了新的记录,导致第一个事务再次读取时结果不一致。

4. 间隙锁的实现

  • 锁定间隙:当事务需要访问一个范围内的数据时,数据库管理系统会在该范围内的记录之间加上间隙锁。
  • 检测间隙:在插入新记录之前,数据库管理系统会检查是否存在间隙锁。如果存在,插入操作将被阻塞,直到间隙锁被释放。
  • 与行级锁的配合:间隙锁通常与行级锁一起使用。例如,当一个事务持有某个范围内的共享间隙锁时,它可以读取这个范围内的记录,但不能修改它们。

5. 间隙锁的兼容性

间隙锁与其他类型的锁(共享锁、排它锁)之间存在兼容性规则。例如:

  • 共享间隙锁与共享锁兼容,但不与排它锁兼容。
  • 排它间隙锁既与共享锁也不与排它锁兼容。

6. 死锁检测

间隙锁的使用也需要考虑死锁检测机制。数据库管理系统会定期检测死锁情况,并采取措施解决,如回滚事务。

7. 间隙锁的释放

间隙锁通常在事务结束时释放,无论是提交还是回滚。这允许其他等待的事务继续执行。

8. 间隙锁的性能影响

虽然间隙锁可以防止幻读,提高数据的一致性,但它们也可能增加锁定的开销,降低并发性能。因此,数据库管理员需要根据具体的业务需求和系统负载来权衡间隙锁的使用。

9. MVCC与间隙锁

在支持MVCC的数据库系统中,间隙锁与MVCC一起工作,以提供更高级别的隔离性。MVCC通过保存数据的多个版本来处理并发读取,而间隙锁确保在这些版本的间隙中不会插入新的记录。

间隙锁是一种重要的锁定机制,特别是在需要防止幻读的场景中。然而,间隙锁的使用需要仔细考虑,以避免不必要的性能损失。数据库管理员应该根据具体的应用场景和事务特性来决定是否使用间隙锁。

4. 一致性非锁定读取:

  • 在可重复读隔离级别下,InnoDB允许事务进行一致性非锁定读取(consistent non-locking reads)。这意味着事务可以读取到一致性视图中的数据,而不需要获取额外的锁。

5. Undo日志:

  • InnoDB使用undo日志来实现MVCC。当事务修改数据时,undo日志会记录数据的旧版本,这样其他事务仍然可以看到未被修改前的数据。

最后

通过这些机制的组合,MySQL的InnoDB存储引擎能够在可重复读隔离级别下提供稳定的数据视图,确保事务的一致性和隔离性。然而,这种隔离级别虽然提供了很好的数据一致性保证,但也可能引起性能问题,如锁的竞争和死锁。因此,在实际应用中需要根据业务需求和性能考虑来选择合适的隔离级别。

相关推荐
MonkeyKing_sunyuhua17 分钟前
ubuntu22.04 docker-compose安装postgresql数据库
数据库·docker·postgresql
天郁青17 分钟前
数据库交互的本地项目:后台管理系统
数据库·交互
小灰灰__19 分钟前
IDEA加载通义灵码插件及使用指南
java·ide·intellij-idea
马剑威(威哥爱编程)23 分钟前
MongoDB面试专题33道解析
数据库·mongodb·面试
夜雨翦春韭23 分钟前
Java中的动态代理
java·开发语言·aop·动态代理
程序媛小果44 分钟前
基于java+SpringBoot+Vue的宠物咖啡馆平台设计与实现
java·vue.js·spring boot
小光学长1 小时前
基于vue框架的的流浪宠物救助系统25128(程序+源码+数据库+调试部署+开发环境)系统界面在最后面。
数据库·vue.js·宠物
掘金-我是哪吒1 小时前
微服务mysql,redis,elasticsearch, kibana,cassandra,mongodb, kafka
redis·mysql·mongodb·elasticsearch·微服务
追风林1 小时前
mac m1 docker本地部署canal 监听mysql的binglog日志
java·docker·mac
芒果披萨1 小时前
El表达式和JSTL
java·el