4.1 版本管理器——2PL与MVCC

2PL协议

2PL(Two-Phase Locking,两阶段锁协议)是数据库管理系统中用于确保事务调度正确性的常见并发控制协议。它通过锁机制来管理事务对数据库资源的访问,确保事务之间不会发生冲突。2PL协议可以分为以下两个阶段:

  1. 扩展阶段(Growing Phase):在这个阶段,事务可以请求获得锁定(如共享锁或排他锁),但不能释放任何锁。事务可以随着操作的进行逐步获取更多的锁,但一旦进入收缩阶段,便不能再获取新的锁。

  2. 收缩阶段(Shrinking Phase):在这个阶段,事务只能释放锁,不能再获得新的锁。一旦事务开始释放锁,就不能再请求新的锁。

2PL锁协议的重要特性是,事务必须在扩展阶段获取所有必要的锁,然后在收缩阶段释放这些锁。这个过程确保了在并发执行多个事务时,数据库的一致性和隔离性。 两阶段锁协议有两种变体

  • 严格两阶段锁协议(Strict 2PL):事务在提交或回滚之前不会释放任何锁,特别是排他锁。这种策略可以防止脏读的发生,确保了更高的隔离级别。

  • 严密两阶段锁协议(Rigorous 2PL):事务在整个生命周期内都不会释放任何锁,直到事务结束(提交或回滚)。这种策略比严格2PL更严格,防止了脏读、不可重复读和幻读。

2PL协议在数据库系统中广泛使用,是确保并发控制、避免死锁和保证数据一致性的重要方法之一。

以上定义来自GPT

数据库中的冲突操作

不考虑插入操作,只考虑updateread操作,这两个操作满足以下三个条件即相互冲突:

  • 两个操作由不同事务执行

  • 两个操作操作同一个数据项

  • 至少有一个update操作

那么对同一个数据项的操作发生冲突的条件其实如下:

  • 两个不同事务的update冲突

  • 两个不同事务的updateread冲突

2PL和解决冲突操作有什么关系?

2PL(两阶段锁协议)在解决数据库中的操作冲突时具有以下重要意义:

1. 确保事务的隔离性

2PL的核心目标是确保多个事务并发执行时保持隔离性,防止事务之间的操作互相干扰。隔离性是ACID(原子性、一致性、隔离性、持久性)原则的重要组成部分,特别是避免以下常见问题:

  • 脏读:一个事务读取了另一个未提交事务修改的数据,导致数据不一致。

  • 不可重复读:一个事务两次读取相同的数据,但在两次读取之间,另一个事务修改了数据。

  • 幻读:一个事务在多次查询时,发现有额外的数据行被另一个事务插入,导致查询结果不一致。

通过2PL协议,事务可以通过锁机制避免这些问题,从而保持数据的一致性和隔离性。

2. 预防操作冲突(重点在这一条)

在并发场景下,不同事务可能对同一资源(如数据库记录)进行操作。如果不加控制,事务间的冲突可能导致数据不一致或事务失败。2PL通过锁来管理资源的访问,避免以下类型的冲突:

  • 读-写冲突:一个事务正在读取数据,另一个事务想要修改该数据。

  • 写-写冲突:多个事务同时尝试修改同一数据。

2PL协议要求事务在扩展阶段获取所需的锁,并保证在释放锁前,其他事务无法访问已被锁定的资源,从而避免了操作冲突。

3. 保证调度的可串行化

串行化调度(Serializable Scheduling)是指事务的并发执行结果与按顺序执行的结果一致。2PL协议是确保调度可串行化的重要手段。根据2PL,事务的锁获取和释放顺序符合两个阶段的规则,这就保证了事务不会相互交错,导致不一致的状态。

4. 避免不安全的调度

如果不使用锁协议,事务调度可能导致不安全的执行。例如,一个事务读取了另一个事务修改的未提交数据,这可能导致数据污染。2PL通过锁定资源,确保每个事务只能在资源安全的状态下执行,从而避免出现不安全的调度情况。

5. 防止死锁(结合其他技术)

虽然2PL本身不能完全避免死锁,但它为死锁检测提供了基础。在2PL中,由于事务可能在扩展阶段请求多个锁,有可能发生死锁(即两个或多个事务相互等待彼此释放锁)。通过结合死锁检测机制或采用诸如超时机制,数据库系统可以检测并解除死锁,恢复正常执行。 上面来自GPT

在MySQL中,两阶段锁协议的含义是:当一个事务获取到了某一个数据库对象的锁之后,并不是当前事务不需要操作它了之后,这个说就会马上释放掉,这个锁会一直被这个事务持有,直到这个事务被提交或回滚后,这个锁才会被释放掉。所以,在当前事务还没有结束的时候,任何其他事务尝试获取这个锁的时候,都会被阻塞。知道当前事务提交或回滚后,前提事务才可以获取到这把锁 这就是MySQL中2PL两阶段锁协议的含义。它在事务并发的时候,为数据的一致性提供有力的保障 源自网络

MYDB中解决冲突的方法

SimpleDB采用2PL来实现调度序列的可串行化。如果某个事务i已经对x加锁,且另一个事务j也想操作x,但是这个操作与事务i之前的操作相互冲突,那么事务j会被阻塞。 使用2PL虽然保证了调度序列的可串行化,但是不可避免地导致了事务间的相互阻塞乃至死锁

MVCC

什么是MVCC

MVCC(Multiversion Concurrency Control,多版本并发控制)是一种数据库并发控制机制,用于解决数据库中多个事务并发执行时的读写冲突问题。MVCC通过维护数据的多个版本,允许并发的读操作和写操作更有效地进行,从而提高数据库的并发性能和系统吞吐量。

核心概念
  1. 版本控制:每个数据项都有多个版本,每个版本对应于数据库在某个时间点的状态。当事务对数据进行修改时,系统不会直接覆盖旧版本的数据,而是创建一个新版本。旧版本的数据仍然保留,以供其他事务读取。

  2. 事务标识:每个事务在开始时都会获得一个唯一的时间戳或事务ID。这个时间戳用于决定事务可以访问哪些数据版本,从而确保数据的一致性和隔离性。

  3. 快照隔离:MVCC提供了一个时间点的数据库“快照”,即事务在开始时看到的是数据的一个一致快照,即使其他事务在此后提交了修改。这个机制确保了读取操作的可重复性,避免了脏读和不可重复读的问题。

MVCC 的工作机制
  • 读取操作:事务在读取数据时,根据自身的时间戳,只能看到在该时间戳之前提交的版本数据。这意味着事务读取的数据版本是相对于其开始时间点的一致快照,而不是实时的最新数据。

  • 写入操作:当事务要修改数据时,系统会创建该数据项的一个新版本,并将该版本标记为该事务的写入。这个新版本在事务提交前,对其他事务是不可见的。

  • 提交和回滚:当事务提交时,系统会将新版本标记为可见,同时其他事务将能够看到这个新版本。如果事务回滚,则新版本会被丢弃,其他事务继续访问旧版本。

优点
  1. 高并发性:MVCC允许多个事务同时读取数据,而不需要加锁。这减少了读写操作之间的冲突,从而提高了并发性。

  2. 避免读写冲突:通过维护数据的多个版本,读操作不会被写操作阻塞,反之亦然。这大大减少了死锁和等待时间。

  3. 一致性保证:MVCC通过时间戳和数据版本管理,确保事务看到的是一致的数据库状态,避免了脏读、不可重复读和幻读问题。

缺点
  1. 存储开销:由于需要维护多个版本的数据,MVCC增加了存储空间的需求。过多的版本还可能需要额外的机制来清理和回收空间。

  2. 版本管理复杂性:随着时间的推移,系统可能产生大量数据版本,管理这些版本及其对应的事务状态会增加系统的复杂性。

使用场景

MVCC广泛应用于现代关系型数据库系统,如PostgreSQL、MySQL(InnoDB引擎)和Oracle,以及一些NoSQL数据库,如Cassandra。它尤其适用于读操作频繁的场景,通过减少锁冲突来提高并发性能。

所以说,MVCC其实是一种思想,在不同的数据库中有不同的具体实现方式

MYDB中的MVCC

之前的实现中,我们知道数据管理器(DM)通过操作持久化的db文件,并通过封装,向上提供的抽象数据是DataItem,也就是说,上层看到的数据都是DataItem的形式 而本章讨论的版本管理器(VM)会进一步封装,给VM之上的模块提供一种抽象数据,即“记录”(Entry)。VM之上的模块看到的数据以及操作的数据都是Entry的形式 VM在内部,为每个Entry维护了多个版本(Version)。当上层模块对某个“记录”(Entry)修改时,VM就创建一个新的版本 如上的MVCC策略能够降低不同操作之间互相阻塞的概率,例如实现可重复读等隔离级别

  • 9
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值