第 1 部分:概述、锁粒度和死锁
最近,我们有一些关于数据库事务的文章,有关强制执行四个 ACID 属性(原子性、一致性、隔离性、持久性)。在今天的文章中,我们将研究关系数据库(RDBMS)用于强制执行 ACID 属性的另一种机制,即对象锁定。具体来说,我们将了解它是什么,它在 RDBMS 事务中扮演什么角色,以及锁定可能导致的一些副作用。虽然数据库对象锁定可能是一个相当技术性和复杂的主题,但我们会以浅白的用语解释它并尽可能简单易明。
什么是对象锁定?
简单地说,对象锁定是一种防止同时访问数据库中数据的方法,以避免数据不一致。为了说明对象锁定的工作原理,假设两个银行柜员试图为两笔不同的交易更新同一个银行帐户。两个柜员都检索(即复制)账户记录。柜员 A 申请并保存一笔交易。柜员 B 将不同的交易应用到自己保存的副本,并保存结果,这一笔交易会覆盖柜员 A 输入的交易。现在记录不再反映第一笔交易,就好像它从未发生过一样!
修复方法是在任何用户修改记录时锁定该记录,使其他用户不能同时更改它。这可以防止记录被错误地覆盖,但一次只允许处理一条记录,从而锁定需要在同一实例中编辑记录的其他用户。因此,任何试图检索相同记录进行编辑的人都会因为锁定而被拒绝写入访问(取决于具体的实现,他们可能仍然能够以只读状态查看记录)。一旦记录被保存(或取消编辑),锁定就会被释放。通过防止保存记录以覆盖其他更改,数据完整性(ACID 中的 I)就得以保持。
锁定粒度
上面的示例演示了一个记录级锁定的实例。现在想象一下,如果上面的两个银行柜员为两个不同的客户提供服务,但他们的帐户都在同一个账本中。在这种情况下,整个账本(或者,一个或多个数据库表)将需要被锁定以进行编辑。可以想象,锁定整个表会导致大量不必要的等待。如果柜员可以从账本中移除一页,其中包含当前客户的帐户(可能还有一些其他帐户),那么可以同时为多个客户提供服务,前提是每个客户的帐户都位于与其他客户不同的页上。如果两个客户在同一页上都有帐户,则一次只能服务一个客户。这类似于数据库中的页级锁定。
有四种类型的锁定。它们的粒度越来越细:
- 数据库锁定
- 表锁定
- 页锁定
- 行锁定
锁定粒度和死锁
粒度锁定的使用使用可能导致称为“死锁”的情况。当使用增量锁定(锁定一个实体,然后锁定一个或多个附加实体)时,可能会发生死锁。例如,我和我的妻子经常在我们的个人帐户之间转账。如果我们每个人都要求柜员获取我们的个人帐户信息,以便我们可以将一些钱转入另一方的帐户,那么这两个帐户基本上会被锁定。然后,当我们的柜员试图将钱转入彼此的帐户时,他们都会发现另一个帐户“正在使用”,迫使他们等待帐户被释放。不知不觉中,两个柜员一直在等对方,直到对方放弃退回帐户,双方都无法完成交易!值得庆幸的是,有人已经设计了各种技术来规避此类问题。这些将在下一部分中讨论。
预告
在今天的文章中,我们知道了什么是关系数据库的对象锁定、不同类型的锁定和死锁。在下一部分中,我们将讨论一些冲突解决策略,以及悲观锁定与乐观锁定。
Rob Gravelle 居住在加拿大渥太华,是一名有 20 多年经验的 IT 专家。过往,Rob 曾为与情报有关的组织(如加拿大边境服务局和各种商业组织)构建系统。在业余时间,Rob 是一名出色的吉他演奏家,他拥有多张 CD 和数字发行版。