DBMS 中的盲写

2025年6月24日 | 阅读 8 分钟

引言

众所周知,在数据库管理系统 (DBMS) 中,当多个用户同时访问数据库时,保持数据一致性是一项严峻的挑战。与此相关的一个重要概念是“盲写”的概念。盲写可能发生在事务在执行过程中没有先读取数据就将数据写入数据库时。

为了更好地理解这一点,想象一下两个人正在处理一个共享文档。如果一个人在不检查现有内容的情况下更新了一个部分,那么他们的更改可能会覆盖另一个人添加的重要信息。同样,在 DBMS 中,盲写可能导致丢失更新或数据不一致等问题,因为事务在写入之前不考虑当前值。

Blind Write in DBMS

通常,DBMS 中的事务遵循一系列读写操作。例如,它可能会读取银行账户的当前余额;然后,它将执行一些计算,然后将更新后的余额写回。然而,在盲写中,事务通常会跳过读取步骤,直接写入新值。这种情况更常发生在事务对要写入的数据有把握,或者系统主要使用默认值的情况下。然而,盲写很容易导致并发问题。由于事务不检查现有数据,它可能会无意中覆盖同一时间运行的其他事务所做的更改。这种风险主要使盲写成为并发控制机制中的一个重要考虑因素,例如有效地锁定各种使用的协议和事务调度

此外,为了妥善处理盲写,DBMS 可以有效地使用各种技术,如严格两阶段锁定 (2PL) 或时间戳排序,以确保事务的执行方式能够保持一致性。这些方法有助于个人防止冲突,并确保最终数据库状态正确反映所有成功的事务。

盲写在数据库管理系统中的作用

盲写是一种操作,在这种操作中,Java 开发人员或应用程序在执行写入操作之前不先检查写入结果。盲目写入可能导致记录被覆盖,或者由于冲突的唯一约束、外键或其他数据库保护而遇到不同的值。未经适当错误处理的特权模式盲写可能会导致数据损坏或其他意外后果。

什么是盲写?

与顺序读写不同,盲写是一种在不先进行读取操作来查找当前数据的情况下更新数据库的操作。例如,应用程序会向数据库发送 UPDATE 或 INSERT 语句,并替换已有的值。

这种技术可以称为盲目写入,因为它涉及在不访问现有信息的情况下进行研究。应用程序不知道它在做什么。它在更改表或行时会盲目地进行操作。

为什么要使用盲写?

应用程序开发人员可能会执行盲写操作,原因主要有两个:

  1. 性能提升 - 每次写操作前的读取都会增加额外的延迟。原始数据可以通过盲写命令进行修改,跳过读取步骤,从而提高操作速度。
  2. 内存一致性 - 当系统发生争用时,会出现这种情况,读取的数据可能在写入之前就已更改,这被称为丢失更新和不正确的结果。可以使用此方法避免或减轻这些盲写。

例如,可以使用增量计数器来实现多线程进程。在每个客户端上执行此增量操作而不读取先前的值,当其他客户端尝试同时更新时,就不会出现增量丢失的情况。

盲写在数据库系统中的工作原理

Blind Write in DBMS

众所周知,在大多数数据库系统中,当数据通过 UPDATE、INSERT 或 DELETE 等操作频繁更改时,系统通常会锁定受影响的数据以保持一切一致。这种锁定确保没有其他事务可以同时更改相同的数据,这有助于防止冲突。然而,在盲写的情况下,会跳过此锁定步骤。盲写直接执行写入操作,而无需提前获取行锁,这可以通过减少等待时间来提高性能。

为了妥善管理盲写,许多数据库通常使用一种称为“多版本并发控制 (MVCC)”的技术。MVCC 不会立即覆盖数据,而是保留数据项的多个版本。这样,如果一个事务正在更新一行,其他读取相同数据的事务仍然可以访问之前的版本。

  • 例如,假设一个客户的地址被一个事务更新了。在这种情况下,读取该客户数据的另一个事务仍然可以看到旧地址,从而有效地维护了数据库的一致视图。

盲写发生后,数据库通常会执行异步检查,以确保没有发生冲突的写入。这意味着系统会在写入后尝试锁定数据,以验证其他事务是否导致了问题,例如脏写或冲突。如果检查发现问题,数据库将返回该操作并要求重新尝试事务。例如,如果一个事务添加了一个订单,但另一个事务在之前删除了同一个订单,那么添加操作将在这次检查中失败。

由于冲突检测是在写入后进行的,因此数据库不能保证即时一致性。其他事务可能会在更改完全确认之前看到这些更改,从而导致最终一致性模型。这意味着数据库最终会变得一致,但可能会出现临时不一致,例如报告显示未提交的近期订单。

为了解决所有这些问题,应用程序需要包含逻辑来在发生冲突时重试失败的写入。通常,会设置重试限制以避免无限循环。

  • 例如,支付系统可能允许最多五次重试,然后才报告错误。

为什么会发生盲写?

开发人员最终执行盲写有几个常见原因:

  1. 懒惰 - 错误在运行时检查,并且要花费大量时间才能找到错误发生的位置,因此,为了节省时间,一些开发人员会跳过错误处理和检查。随后,由于有人认为没有必要麻烦,便发生了公然的抄袭。
  2. 假设 - 开发人员可能只是假设写入会成功,因此他们可能不想在写入之前验证约束。但是,如果他们的预测被证明是错误的,或者情况不再与他们设想的相同,盲写可能会失败。
  3. 竞争条件 - 设计并发应用程序时最常见的问题之一是所谓的竞争条件。在这种情况下,开发人员可以检查写入是否会成功,然后确定此写入是安全的,但当实际写入在稍后发生时,情况可能已经改变,并且写入现在可能会失败,因为在检查和写入之间发生了另一个操作。在这种情况下,可能会发生计划外的停电。

风险和缺点

然而,盲写也带来了显著的缺点:

  • 覆盖关键数据 - 举例来说,现有的应用程序数据可能在不知道的情况下被擦除或损坏。操作方式不知道现有状态在哪里。
  • 重复条目 - 在数据插入期间,数据库可能会无意中产生重复或违反主键的情况,因为它对此并不知情。
  • 参照完整性问题 - 可能会发生数据被插入或更新的方式影响了依赖于它的其他表。这可能导致数据失衡和孤立,从而无用。在处理外键关系时可能发生的主要问题之一是它们很容易损坏。
  • 因竞争条件而产生的错误 - 在测试环境中运行良好但但在生产环境中,当在高并发多用户负载下运行时,可能无法正常工作。

盲写者的八个顶级手动实践

但是,基于这些危险,应尽可能避免盲写操作。一些技巧:

  • 实现自动和修复步骤以定期执行,旨在清理现有的重复或孤立记录。
  • 在所有可能的情况下,使用索引来加快搜索速度,并应用主键和外键设置,以减少损坏数据库的可能性。
  • 当更新的幂等性或其可重复性和排序不影响数据库状态时,盲写会占据优势。
  • 具有管理员警报和日志记录,这有助于检测可能升级为完整性违规的盲写问题。
  • 在进行盲写更新时添加版本号/时间戳等功能,这将允许应用程序警惕丢失的更新或并发冲突,这些冲突由应用程序确认,而不是静默更新。

从根本上说,无损压缩是为了提高速度而牺牲数据完整性。与它们一样,还有其他NoSQL数据库,它们更看重吞吐量而不是一致性。要决定是否使用盲写技术是关键,我们需要评估应用程序的并行模式、性能需求以及对暂时性数据错误的容忍度。由于读前写比盲写技术成本更高,因此工程团队应仅在数据错误无法长时间存在的情况下选择读前写。通过适当的技巧组合,我们可以实现更具弹性和健壮性的系统,这些系统有可能防止数据的大规模丢失或损坏。

常见问题解答

关于盲写在 DBMS 中使用的各种常见问题如下:

问题 1:数据库管理系统中的盲写是什么意思?

回答:众所周知,当事务在不先读取现有值的情况下将数据写入数据库时,就会发生盲写。在这种情况下,它只是更新、插入或删除一行,而无需检查其当前状态。这会提高性能,但如果其他事务同时访问相同的数据,则可能导致问题。

问题 2:为什么盲写在多用户环境中存在风险?

回答:当多个事务试图更改相同的信息时,盲写可能导致数据冲突。由于系统不会提前检查数据,一个事务可能会在不知不觉中覆盖另一个事务所做的更改。如果管理不当,这可能导致丢失更新或不一致的记录。

结论

由于盲写是数据库系统设计中最重要的权衡之一,因此它是牺牲一致性写入操作来获得可用性和性能的选择。代理商会盲目竞价数据,而对结果一无所知,从而提高其吞吐量和并发级别,同时依靠应用程序级别的机制来处理中止的写入事务。它允许数据处理引擎有效地同时处理数百万个处理和修改数据集,从而将系统复杂度推向应用程序级别。尽管存在许多替代的并发方法,但大多数最流行的传统数据库仍然基于盲写方案。