为确保数据完整性,所有数据库管理系统 (DBMS) 都采用了数据锁定机制。例如,当某个用户开始更新某些行时,这些行即会锁定,以防止其他用户进行更改。当事务完成后,锁定就会解除。
每个 DBMS 锁定和解释隔离级别的方式都各不相同,而且 ArcGIS 处理所有 DBMS 的方式也不尽相同。因此,在不同的 DBMS 间,执行非版本化编辑时出现并发问题的可能性会略有不同。本主题简要介绍了在 ArcGIS 上下文中并发与锁定的机制。有关详细信息,请参阅您的 DBMS 文档。
ArcGIS 与隔离级别
当您在非版本化的编辑会话中编辑 Oracle、DB2 或 Informix 地理数据库时,ArcGIS 使用与任何其他应用程序中都相同的底层 DBMS 锁定机制,ArcGIS 不会自行设置隔离级别来更改此环境,而是使用在 DBMS 中设置的当前隔离级别。因此,在非版本化的编辑会话中进行编辑时,您可以将隔离设置为任何级别并进行使用。
当您在非版本化的编辑会话中编辑 SQL Server 地理数据库时,ArcGIS 会在每个事务开始前将隔离级别设置为“未提交读取”。ArcGIS 的这一行为无法更改也无法摆脱;如果在某个事务开始前将隔离设置为另一级别,则在该事务开始前 ArcGIS 会自动将隔离级别设置回“未提交读取”。
以下几节介绍了在通常条件下可能发生的并发问题。除非另有说明,否则本文中所述内容均假设已在底层 DBMS 中将默认隔离级别设置为“提交后读取”或与之相当的级别。
Oracle
写入者阻止写入者:对某个要素或一组要素执行编辑操作(例如,移动要素或修改其属性)时,DBMS 会将行锁定。要素将一直处于锁定状态,直到进行了保存或停止编辑且未保存。因此,在编辑会话期间,您所编辑的所有要素或记录都将处于锁定状态。
当两个用户试图同时编辑同一要素时,该要素会在第一个用户完成某个操作后锁定。锁定状态会继续保持,即使该用户去处理其他要素。要素会保持锁定状态,直到该用户执行保存操作(从而将其所做的更改提交到数据库),或停止该编辑会话并放弃保存(从而回滚在该编辑会话中执行的所有编辑)。
当要素处于锁定状态时,第二个用户试图修改同一要素。第二个用户的 ArcMap 会话会等待锁定解除,并会显示熟悉的沙漏。沙漏会一直显示直到锁定解除,即直到第一个用户保存更改(将更改提交到数据库)或结束编辑会话并放弃保存(回滚编辑)。此时,第二个用户屏幕上的沙漏消失,并且可以开始编辑操作。(请注意,这意味着第二个用户的编辑将覆盖第一个用户的编辑。)
当出现以下情况时,在两个用户之间也会同时发生这种锁定问题:
- 两个用户同时进行编辑。
- 两个用户已在各自当前编辑会话中修改了行。
- 每个用户都试图修改一个已被另一个用户修改过的行。
两个用户中第一个试图修改已锁定行的用户将看到一个沙漏,表示 ArcMap 会话将等待锁定解除。当第二个用户试图修改已被第一个用户锁定的行时,就会出现被称之为死锁的情况,因为两个用户都在同时阻止对方。DBMS 会立即选择将其中一个事务回滚,以便另一个用户能够继续操作。事务被回滚的用户必须重做自上次保存编辑后执行的所有编辑。
写入者不阻止读取者:无论隔离级别如何设置,将数据写入到数据库的用户都不会阻止其他用户读取同一的数据。对于读取被锁定数据的用户,数据将显示为在当前事务开始前的状态。
读取者不阻止写入者:在任何隔离级别上,读取数据库的用户都不会阻止其他用户修改同一数据。
DB2 和 Informix
写入者阻止写入者:DB2 和 Informix 中写入者阻止写入者的方式与在 Oracle 中类似。有关详细信息,请参阅“Oracle”下的说明。
写入者阻止读取者:在 DB2 和 Informix 中,在位于“未提交读取”之上的任何隔离级别,写入者都将阻止其他用户读取同一数据。在这些更高的隔离级别上,在保存或回滚编辑之前一直锁定数据可能会导致并发问题,也就是说,当您处理编辑会话时,其他人将无法读取您正在编辑的数据。这可能会导致出现以下情况:
- 如果另一用户向 ArcMap 中添加相同的图层,会出现沙漏,且只有锁定被解除后才能绘制图层。
- 如果另一用户试图平移到正被编辑的数据,ArcMap 会等待锁定解除,之后才会更新显示。
- 如果另一用户标识一个锁定的要素,则会出现沙漏,并且直到锁定解除之后才会返回信息。
读取者阻止写入者:在 DB2 和 Informix 中,在位于“未提交读取”之上的任何隔离级别,读取者都将阻止其他用户修改同一数据。不过,实际上在 ArcGIS 中却很少见到这种情况,这是因为读取行锁定的持续时间很短,而当数据出现时锁定就已经被解除了。只有在以下应用中,读取者才能真正地阻止写入者:在 DBMS 中打开游标、每次提取一行并在其处理数据时遍历整个结果集。此时,DB2 和 Informix 会在处理结果集时开始获取并保持锁定状态。
PostgreSQL
写入者阻止写入者:在 PostgreSQL 中,直到对行进行了更改的首个事务已提交到数据库或回滚时,才能更新行。当两个用户试图同时编辑同一要素时,第一个用户会阻止另一个用户对该行进行更新。在该用户执行保存操作(从而将更改提交到数据库),或停止编辑会话并放弃保存(从而回滚在该编辑会话中执行的所有编辑)之后,其他用户才能编辑该行。
当要素处于锁定状态时,第二个用户试图修改同一要素。第二个用户的 ArcMap 会话会等待锁定解除,并会显示熟悉的沙漏。沙漏会一直显示,即直到第一个用户保存更改(将更改提交到数据库)或结束编辑会话并放弃保存(回滚编辑)。此时,第二个用户屏幕上的沙漏消失,并且可以开始编辑操作。(请注意,这意味着第二个用户的编辑将覆盖第一个用户的编辑。)
写入者不阻止读取者:如果使用 PostgreSQL 的多版本并发控制 (MVCC)(此为数据库的默认和推荐行为),则写入到数据库的用户事务不会阻止读取者查询数据库。无论您是在数据库中使用默认的隔离级别“读取已提交”,还是将隔离级别设置为“序列化”,都不会阻止。
读取者不阻止写入者:无论在数据库中设置何种隔离级别,读取者都不会锁定数据。
SQL Server
ArcGIS 会在 SQL Server 地理数据库中每个事务开始前将隔离级别设置为“读取未提交”。下面将介绍在 ArcGIS 环境中可能出现的并发问题。有关“读取未提交”隔离级别的详细信息,请参阅 SQL Server 文档。
写入者阻止写入者:SQL Server 中写入者阻止写入者的方式与在 Oracle 中类似。有关详细信息,请参阅“Oracle”下的说明。
写入者不阻止读取者:由于 ArcGIS 会在每个事务开始前将隔离级别设置为“读取未提交”,因此在 SQL Server 地理数据库中写入者不会阻止读取者。不过,如果在某些用户修改数据的同时另一些用户正在读取同一数据,则用户可以读取已被更改但尚未提交的数据。这称之为脏读,它可能会导致从查询返回以下内容:
- 不准确的数据值
- 存在数据时不返回数据
- 不存在任何内容时返回重复数据
读取者不阻止写入者:由于 ArcGIS 会在每个事务开始前将隔离级别设置为“读取未提交”,因此在 SQL Server 地理数据库中读取者不会阻止写入者。
避免并发问题
幸运的是,可通过多种方式来将并发问题降至最少:
设计应用和工作流时兼顾考虑锁定机制:等待锁定解除的请求常常由应用或工作流的设计欠佳所导致。开发应用或工作流时,应确保锁定请求有序进行。可以通过标准化所有表的更新顺序来实现这一目的,并且能够避免死锁。要缩短锁定的持续时间,最好在执行事务的应用逻辑或工作流单元完成后发出所有数据修改请求。
设置适当的隔离级别(Oracle、DB2、Informix):隔离级别会影响事务锁定数据的时间长短。隔离级别越高,事务锁定的持续时间越长。事务锁定的持续时间越长,数据的完整性就越好,但这样就要减少并发。只要在可接受范围内,可以通过降低隔离级别来改善并发。
将数据注册为版本:通过将数据注册为版本从而可以将编辑内容移到基表,进而改善并发。这样,用户可在不使用 ArcGIS 的应用程序中维护数据,从而增强 ArcGIS 和 ArcObjects 应用程序用户编辑和管理多版本数据的能力,否则这些用户可能会导致并发问题或受到其影响。当用户编辑某个版本的数据时,不使用锁定机制,从而使数据在与其他用户完全隔离的情况下进行编辑。
数据库锁定是一个复杂的课题。而且,每个 DBMS 执行锁定的方式各不相同。因此,您需要通过研究您所使用的 DBMS 的行为来确定上设置何种锁定级别、如何设置隔离级别以及如何处理锁定超时及死锁情况。