乐观并发与悲观并发的区别

2025年4月21日 | 6分钟阅读

本文讨论了乐观并发悲观并发之间的区别。

并发控制是数据库系统提供的另一项属性,它为多个事务同时运行而不发生干扰提供了隔离。并发控制可以分为悲观乐观两大类。这两种方法哪种更好,取决于检测或解决事务冲突的方式。本文将解释这些方法,并分析每种方法的优点、缺点和适用场景。

什么是乐观并发?

乐观并发允许事务在不锁定资源的情况下进行。它允许多个事务继续进行,而最初不锁定资源。可能会发生一些冲突,但可以在事务完成后解决。每个事务独立运行,并假设其他事务不会对其产生太大影响。

这种方法在事务尝试提交后检测冲突。当事务完成后,它会检查它所操作的数据是否已被其他事务修改。如果没有冲突,事务将提交;如果因冲突而未能通过检查,则事务将被中止,并可能重试。

乐观并发机制

  • 无锁定:事务期间不锁定数据,允许其他事务访问。其他事务可能会访问和修改此事务正在更改的数据。
  • 版本控制:通常使用版本控制系统来检测冲突(例如,数据行的存储时间戳或版本号)。
  • 冲突解决:在提交时,系统会检查是否有其他事务对其进行了更改。发生冲突时,它会回滚两个竞争选项中的一个事务,并可能尝试重试。

示例

  • 通用数据库:锁定的限制在分布式系统中很常见,因为这些锁有时会成为瓶颈并降低性能。
  • 最终一致性:NoSQL数据库(例如CassandraMongoDB)这样的系统通常依赖乐观并发机制来实现一段时间内的一致性。

乐观并发的优点

乐观并发有几个优点,如下所示:

  • 在写冲突率低的系统中,吞吐量会更高。
  • 并发性更高,因为没有锁会阻塞其他事务。
  • 它在分布式系统环境或大多数事务是只读的环境中提供更好的性能。

乐观并发的缺点

  • 高冲突下的频繁回滚可能会损害性能。
  • 它需要复杂的冲突解决机制来处理事务进行过程中已更改的数据。

什么是悲观并发?

悲观并发控制假设最有可能发生冲突。它是锁定资源以避免冲突的机制。当事务想要访问数据项时,它首先对其加锁;因此,在释放锁(通常在事务完成时发生)之前,没有其他事务可以访问、读取或修改相同的数据项。

该机制确保一次只有一个事务作用于特定的数据项,以牺牲并发性为代价来控制冲突。任何希望访问被锁定资源的任何部分的事务都必须等待锁被释放。

悲观并发机制

  • 锁:事务开始时锁定资源(数据库中的行、表)。用于履行事务的锁定资源在锁释放之前不能被其他事务访问。
  • 死锁:当两个或多个事务等待对方释放锁时,可能发生死锁,尤其是在它们试图访问彼此的对象时。
  • 阻塞:任何请求锁定资源的事务要么被阻塞,要么必须等待锁释放,从而导致事务执行的序列化。

示例

  • 银行系统:涉及银行系统的金融活动通常使用悲观并发控制。其使用尤其适用于需要保证数据完整性的系统,其中自然需要避免冲突(例如,账户之间的资金转账)。
  • 库存管理:管理库存水平的系统依赖锁来确保没有两个事务同时获取同一库存的资源。

悲观并发的优点

  • 它通过防止冲突更新来确保数据完整性。
  • 由于提前避免了冲突,因此减少了回滚次数。

悲观并发的缺点

  • 由于锁定开销,性能下降,尤其是在高并发系统中。
  • 当两个或多个事务相互等待对方的锁时,会发生死锁。
  • 由于其他事务在等待锁释放,并发性降低。

乐观并发与悲观并发的关键区别

乐观并发悲观并发之间有几个关键区别。一些主要区别如下:

特性乐观并发悲观并发
并发控制可以假设多个事务可以无冲突地完成,并在进行更改之前设置冲突检查点。可以假设很可能发生冲突,并且在事务完成之前阻止其他人访问数据。
锁定读取时没有锁定;冲突主要在更改提交时检测。立即应用锁以防止其他人在运行时访问相同的数据。
冲突检测冲突将在提交更改时检测。通过锁定整个资源来抑制冲突。
用例最适合冲突较少的环境:数据之间的冲突很少见。最适合高度冲突的环境,其中相同的数据被频繁读取或修改。
性能通常更好,因为没有锁的开销;但是,重试或回滚次数可能会增加。锁定可能导致性能缓慢,但可以避免回滚或重试。
死锁风险没有死锁风险,只要过程中没有获取锁。如果同时获取多个锁,在这种情况下,可能存在死锁的风险。
事务回滚仅在提交时因冲突而回滚。由于有锁可以防止冲突事务,因此回滚变得不那么普遍。
复杂度可能需要一些额外的逻辑来处理提交时的冲突。更简单,因为它依赖锁定机制来防止冲突。
可扩展性它通常在低锁开销的高并发系统上表现良好。由于锁定,在许多并发事务的系统中性能不太好。
对其他事务的影响对其他事务的影响较小,因为它允许所有事务并发运行直到提交。它可能会阻塞其他试图访问相同资源的事务,并且即使在没有冲突的情况下,如果事务的所有资源都处于使用状态,也可能出现延迟。
冲突恢复通常依赖于在冲突时重试事务。冲突通常是预先防止而不是解决的,因此重试以继续成功运行事务的可能性通常不存在。
死锁检测没有死锁发生,但如果发生冲突,可能会重试。由于表锁和行锁可能导致死锁,从而在事务之间产生循环依赖,因此需要死锁检测和处理机制。

结论

总而言之,乐观悲观并发模型都有其优点,并且适用于不同的系统。乐观并发适用于读取量大、冲突少的区域,由于没有阻塞,因此在冲突时回滚,从而提高了吞吐量。此类系统的示例是分布式数据库或 NoSQL 数据库,其中最终一致性是可以容忍的。另一方面,悲观并发非常适合高冲突环境,并且对数据完整性有很强的要求,例如银行或库存系统,在这些系统中,它会尽早阻塞资源以避免冲突。然而,由于阻塞的开销和死锁的可能性,它可能会导致性能下降。根据系统的性能、一致性以及它如何处理冲突,应根据系统的性质来做出决定。