Oracle 和 DB2 比较与兼容性/进程模型/锁定
隔离。
当您在数据库上拥有超过一个用户时,您必须拥有一个机制来防止他们同时访问相同的数据。交易对内存中数据的更改方式、这些更改如何记录以及这些内存中的更改如何写入磁盘,都有一个顺序。每个步骤都需要一定的时间来执行,并且一些步骤旨在规避昂贵的 I/O 操作——更改不会在进行时写入,它们将被保存起来,以便可以一举写入一组更改。此操作序列中的每个步骤都需要时间,如果数据库正在为多个用户提供服务,则来自一个用户的更改有机会影响来自另一个用户的更改。随着现代高速处理器的出现、延迟写入以及众多并发用户,这种事件发生的可能性急剧增加,但它只需要发生一次就会成为一个大问题。
此类问题的示例是,如果两个用户读取和更改相同的数据,如果没有控制,则最后写入更改的用户“获胜”——他们将覆盖另一个用户所做的更改。此类问题称为丢失更新。
Oracle 和 DB2 处理此问题的方式是使用锁定——首先锁定要更新的记录。与数据库操作的许多方面一样,使用锁时存在权衡,这种权衡是,如果您锁定数据库的大部分,数据库将很快变得无法使用。为了解决这个问题,数据库在数据库内采用不同级别的锁定,以及不同的锁定和锁升级策略。此概述描述了数据库在其锁定策略中需要考虑的各种情况,Oracle 和 DB2 的各个部分描述了它们如何实施这些策略。
问题
当用户在没有任何控制的情况下读取和写入相同数据时,会发生以下问题
• 幻读——一个事务读取多个行,而另一个独立事务删除或添加行。如果第一个事务发出完全相同的读取,它将获得不同的行数。
• 脏读——一个事务读取来自另一个事务的未提交数据。
• 丢失更新——一个事务中的更新覆盖了另一个事务中的数据。
• 不可重复读——一个读取数据的两次事务不应该在其他事务读取之间发生数据更改。
需要注意的是,不仅仅是 DML 会改变数据库,像 Drop 或 Alter 这样的 DDL 也会改变表。您的锁定策略需要针对 DDL 更改以及 DML 更改。
许多数据库操作都涉及游标。游标是用于遍历一组返回行的设备——它是指向您在集合中的位置的指针。锁定需要满足游标操作,以便对集合中的行(插入和删除)的更改不会中断游标处理,这种中断称为游标不稳定,当大量用户可以同时获取大量行时,这是一个特别敏感的区域。在这种情况下,用户不会影响单行数据,而是影响多行数据。如果您有许多用户这样做,实施不当的锁定策略可能会使数据库陷入瘫痪。
解决方案
为了避免这些问题,ANSI/ISO SQL 标准定义了许多隔离级别
SERIALIZABLE. 所有事务都像串行发出一样执行(即一个接一个)。即使 DBMS 可以同时执行多个事务,这也适用,就所有意图和目的而言,事务执行就像它们完全隔离一样。
REPEATABLE READ. SELECT 读取的所有行都不能更改。但是,如果 SELECT 具有范围 WHERE 子句,则可能会发生幻读,因为此隔离级别会在所有检索到的数据上获取读锁,但不会获取范围锁。
READ COMMITTED. 在 SELECT 语句中检索的数据可能会被修改,因此可能会发生不可重复读取。这是因为读锁是在选定的数据上获取的,但它们会立即释放,而写锁是在事务结束时释放的。
READ UNCOMMITTED. 一个事务可能会看到另一个事务所做的未提交更改。
DBMS 的默认隔离级别各不相同,大多数供应商允许用户更改隔离级别并在其 SELECT 语法中指定不同的锁。
隔离级别是平衡需要维护读取一致性的多用户数据库的需求的一种方法。这是一个双重问题,首先您需要了解供应商采用的方法,然后您需要了解在您正在使用的系统中实施了哪些方法(以及原因)。