MVCC、悲观锁、乐观锁

MVCC

多版本并发控制(MVCC, Multi-Version Concurrency Control)是数据库管理系统中用来实现高并发性和事务隔离性的技术。MVCC允许不同的事务看到数据库中同一数据的不同版本,从而实现了在保持数据一致性的同时,减少了锁的需求,提高了并发性。

MVCC 的核心原理:

  1. 数据版本
    • 每次数据被修改时,不是覆盖旧数据,而是创建新的数据版本。这意味着每个数据项可以有多个版本,每个版本都与特定的事务修改关联。
    • 数据版本通常通过添加系统版本号或事务ID标记实现。这些标记指明了数据版本的创建时间。
  2. 事务ID
    • 每个事务在开始时被分配一个唯一的递增事务ID。这个ID不仅用于标识事务,也用于决定数据版本的可见性。
  3. 版本控制规则
    • 事务在执行读操作时,只能看到ID小于或等于自己事务ID的数据版本,且这些数据版本是在该事务开始之前就已经提交的。这确保了事务的隔离性和一致性视图。
  4. 隐藏版本链
    • 每个数据项可能有多个版本,这些版本通过“版本链”链接在一起。当事务需要访问数据时,它会根据自己的事务ID和数据的版本信息沿这个链查找,直到找到适合自己读取的数据版本。

MVCC 如何实现事务隔离级别:

  • 读未提交(Read Uncommitted):这是最低的隔离级别,事务可以看到其他事务未提交的更改。
  • 读已提交(Read Committed):事务只能看到已经提交的更改。通常实现方式是在每个SQL查询开始时创建一个新的快照。
  • 可重复读(Repeatable Read):事务在启动时创建一个数据快照,并在整个事务期间使用这个快照。这样保证了事务可以多次读取同样的数据。
  • 串行化(Serializable):这是最高的隔离级别,通过锁和其他机制确保事务串行执行。

MVCC 写操作的锁定需求

在 MVCC 中,写操作通常涉及以下步骤:

插入操作: 通常涉及添加一个新的行版本,这通常不需要锁定整个表或行,因为新行版本只对写入事务可见,直到事务提交。
更新操作: MVCC 系统在更新数据时会创建一个新的数据版本。这通常需要行级锁(行锁)来保证在更新过程中其他事务不能同时修改同一行。更新完成后,旧版本仍对其他事务可见,直到它们也结束或需要新的数据版本。
删除操作: 和更新类似,删除通常标记一个行版本为“已删除”,而不是实际从物理存储中立即删除。这也需要行级锁以避免并发删除冲突。

隔离级别和锁定

不同的事务隔离级别对写锁的需求也不同:
读已提交(Read Committed): 这个级别下,写操作会在执行时锁定目标行,直到事务提交。这可以防止读取未提交数据(脏读)。
可重复读(Repeatable Read): 在这个级别下,MySQL 的 InnoDB 存储引擎例如,会使用next-key锁(锁定索引记录和间隙)来避免幻读。
串行化(Serializable): 这是最严格的隔离级别,通常需要更广泛的锁定机制,如表锁,以避免任何并发访问。

MVCC 和锁的优化

尽管MVCC减少了读操作的锁需求,但它通过如下方式优化写操作:

非锁定读: 读操作不会因为写操作而阻塞,反之亦然(在大多数情况下,除了最高隔离级别)。
行级锁: 写操作通常只锁定必要的行而不是整个表,提高了并发性。

MVCC 的优势与挑战:

优势

  • 提高了并发性,因为读操作通常不需要锁定资源。
  • 减少了锁竞争,尤其是在读多写少的应用场景中。

挑战

  • 维护多个版本的数据增加了存储开销。
  • 必须定期清理旧的数据版本,这个过程称为“垃圾回收”,以避免性能下降。

InnoDB的MVCC实现细节

隐藏列

InnoDB为每个行记录自动添加三个隐藏的字段来支持MVCC:

  • DB_TRX_ID:存储最后修改行的事务ID。
  • DB_ROLL_PTR:回滚指针,指向这个记录的上一个版本(undo log的一部分)。
  • DB_ROW_ID:如果表没有定义主键,InnoDB会自动创建一个隐含的行ID。

Undo Log

Undo log用于存储旧的数据版本,当行记录被更新或删除时,其原始版本会被存储在undo log中。这允许InnoDB在需要时重建旧的数据版本,例如当其他事务需要访问早期版本的数据时,或者在事务回滚时恢复数据。

Read Views

Read view用于实现可重复读(REPEATABLE READ)和读已提交(READ COMMITTED)的隔离级别。Read view维护了活跃事务的列表,这样可以确定哪些数据版本对当前事务是可见的。

版本控制如何工作

当事务读取一行数据时,InnoDB执行以下步骤来决定哪个版本的数据是可见的:

  1. 检查DB_TRX_ID:如果行的DB_TRX_ID小于当前事务的ID,且该修改事务已提交,则当前事务可以看到此行。
  2. 使用Undo Log:如果DB_TRX_ID指示该行是由一个尚未提交的事务或较晚的事务修改的,则InnoDB会使用undo log查找该行的一个先前版本,直到找到一个对当前事务可见的版本。

隔离级别的实现

  • 读已提交(READ COMMITTED):每次查询都会创建一个新的read view。
  • 可重复读(REPEATABLE READ):事务开始时创建一个read view,并在整个事务中使用。

快照读与当前读

  • 快照读(Snapshot Read):读取的是记录的可见版本,不需要当前数据。SELECT操作(未使用锁定读)通常执行快照读。
  • 当前读(Current Read):需要访问记录的最新版本,并对其加锁。UPDATE、DELETE、INSERT和SELECT … FOR UPDATE等操作执行当前读。

悲观锁/乐观锁

乐观锁和悲观锁是数据库管理和并发控制中两种常用的锁定策略,用于确保数据的一致性和完整性。它们的使用取决于对数据冲突发生的预期以及所需的性能效率。

悲观锁

悲观锁(Pessimistic Locking)基于这样的假设:冲突在并发环境中是常见的,因此最好通过锁定机制来防止其他事务在一个事务完成前对同一数据进行修改。悲观锁通常直接在数据库的锁管理器中实现。

特点

  • 直接锁定数据:在数据被读取或修改期间,悲观锁会锁定数据对象,阻止其他事务对这些对象的访问,直到锁被释放。
  • 防止数据修改:确保在数据操作期间,无其他事务可以修改或删除数据,从而避免数据冲突。
  • 可能引起阻塞和死锁:由于数据被锁定,其他需要访问这些数据的事务必须等待锁释放,这可能导致系统效率低下,并有可能发生死锁。

适用场景
悲观锁适用于写操作多、冲突概率高的环境,特别是在数据争用条件较多的场合。

乐观锁

乐观锁(Optimistic Locking)是一种更加灵活的锁定策略,它基于这样的假设:数据冲突在并发环境中相对罕见,因此可以在事务结束时检查是否存在冲突,而不是在开始时就锁定数据。

特点

  • 不立即锁定数据:乐观锁不会在数据读取时立即锁定,而是允许多个事务对数据进行预修改。
  • 使用数据版本控制:乐观锁通常通过数据版本号(versioning)或时间戳来实现。每次修改数据时,版本号增加。事务提交前检查版本号是否变化,如果变化了,表示其他事务已修改过数据,当前事务需要回滚。
  • 避免阻塞和死锁:因为不是通过锁来控制访问,所以不会引起事务阻塞和死锁的问题。

适用场景
乐观锁适用于读操作多、写操作少且冲突概率低的环境。

总结

MySQL的MVCC

定义与作用:
MVCC(多版本并发控制)是MySQL中InnoDB存储引擎使用的一种技术,旨在提高数据库在多用户环境中的并发性能。通过为每个数据项创建多个版本,MVCC允许不同的事务看到数据库的不同“快照”,这减少了读写冲突的可能性,并允许读操作不受写操作的阻塞。

原理:

  • 数据版本:每当数据被修改时,InnoDB存储引擎不会直接覆盖原有数据,而是创建一个新的版本(通过增加事务ID和使用undo日志)。
  • 事务隔离:基于事务的开始时间和数据的版本号,MVCC控制一个事务是否可以看到某个数据版本。这使得事务可以操作一个一致性视图,而不会看到其他并发事务正在做的修改。

MySQL中的悲观锁

定义与作用:
悲观锁是一种用于管理数据库并发控制的锁机制,假设冲突发生的概率很高,因此在数据处理之前就通过锁定来避免其他事务的干扰。这是传统的防止数据冲突的方法。

原理:

  • 锁类型:包括行锁(如记录锁、间隙锁和临键锁)和表锁,InnoDB优先使用更细粒度的行锁来降低锁争用。
  • 锁机制:当事务需要修改或读取数据(取决于隔离级别和具体的SQL命令)时,InnoDB会自动加锁阻止其他事务访问这些正在修改的数据,直到当前事务提交或回滚。

MVCC和悲观锁的协同工作

并发控制

  • MVCC优化读操作:MVCC通过允许事务访问旧的数据版本来优化查询操作,从而无需等待其他事务的写操作完成。这主要体现在读操作中,如默认的REPEATABLE READ隔离级别下的普通SELECT。
  • 悲观锁优化写操作:对于写操作,如UPDATE、DELETE和INSERT,InnoDB使用悲观锁来保证数据的完整性和一致性。这些操作需要排他控制,以防止数据在事务完成前被其他事务修改。

锁与MVCC的互补

  • 在REPEATABLE READ隔离级别下,InnoDB通过MVCC提供一致性读取,而通过悲观锁来管理写操作的冲突。读操作不会被写操作阻塞,但写操作仍然需要锁来处理并发写冲突。
  • 在READ COMMITTED隔离级别下,写锁的持续时间较短,且每次查询都会基于最新提交的数据生成一个新的快照。

MVCC和悲观锁在MySQL中是并存的,它们各自发挥作用以优化并发性能和数据一致性。MVCC主要减少读操作中的锁需求,提高读操作的并发性;而悲观锁则确保写操作的安全和数据的一致性。这两者的结合使得InnoDB能够高效地处理各种并发数据访问和修改场景。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

LIHAORAN99

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

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

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

打赏作者

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

抵扣说明:

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

余额充值