写入和读/写操作
可通过决定何时以及如何运行不同类型的命令来管理并发写入操作的特定行为。以下命令与此讨论相关:
-
COPY 命令,可执行加载(初始或增量)
-
INSERT 命令,可一次性追加一个或多个行
-
UPDATE 命令,可修改现有行
-
DELETE 命令,可删除行
COPY 和 INSERT 操作是纯写入操作,而 DELETE 和 UPDATE 操作是读/写操作。(要删除或更新行,必须先读取行。) 并发写入操作的结果取决于同时运行的具体命令。针对同一个表的 COPY 和 INSERT 操作将保持等待状态,直到解除锁定,然后它们将正常继续。
UPDATE 和 DELETE 操作的行为方式不同,因为它们在执行任何写入操作前依赖最初的表读取。由于并发事务彼此不可见,因此,UPDATE 和 DELETE 必须读取上次提交的数据的快照。当第一个 UPDATE 或 DELETE 解除其锁定时,第二个 UPDATE 或 DELETE 需要确定它将使用的数据是否可能已过时。它不会过时,因为第二个事务不会在第一个事务解除其锁定之前获取其数据的快照。
并发写入事务的潜在死锁情况
只要事务涉及多个表的更新,同时运行的事务就始终可能在同时尝试写入同一组表时变为死锁状态。事务会在提交或回滚时一次性解除其所有表锁定;而不会逐一放弃锁定。
例如,假设事务 T1 和 T2 在大致相同的时间开始。如果 T1 开始对表 A 进行写入且 T2 开始对表 B 进行写入,则两个事务均可继续而不会发生冲突;但是,如果 T1 完成了对表 A 的写入操作并需要开始对表 B 进行写入,它将无法继续,因为 T2 仍保持对 B 的锁定。相反,如果 T2 完成了对表 B 的写入操作并需要开始对表 A 进行写入,它也无法继续,因为 T1 仍保持对 A 的锁定。由于两个事务都不能在提交其所有写入操作之前解除其锁定,因此两个事务都不能继续。
为了避免这种死锁情况,您需要小心安排并发写入操作。例如,您应始终在各事务中按相同顺序更新表,如果指定了锁定,则应先按相同的顺序锁定表,然后再执行任何 DML 操作。