首页 > 解决方案 > 插入和相应的触发器调用是原子过程吗?

问题描述

我有一个名为的表LOCK,我想确保不超过一行具有给定名称和类型的WRITE存在。尽管READ允许具有 type 和相同名称的多行,但前提是没有具有相同 name 和 type 的行WRITE

create table "LOCK"
(
    "LOCK_ID" NUMBER(19,0) NOT NULL,
    "NAME" VARCHAR2(255 CHAR),
    "TYPE" VARCHAR2(32 CHAR),
    CONSTRAINT "SYS_LOCK_PK" PRIMARY KEY ("LOCK_ID")
);

插入一行必须是原子的,例如,根据查询的结果,没有带有后续插入的查询(因为它可能同时发生了变化)。

为了确保原子性,我创建了一个触发器来检查最初提到的条件(失败时引发错误),它偶尔会以各种无效状态结束,比如两WRITE行。

如果按顺序执行插入,则触发器可以完美运行,这导致假设插入 + 触发器不是原子过程,如果是这样,是否有安全的方法来解决我的问题?

这是触发器:

create or replace trigger "LOCK_TRIGGER"
before insert on "LOCK" 
referencing NEW AS NEW
for each row
declare
    c   integer := 0;
begin
    select count(*) into c from "LOCK" where (:NEW.typ = 'WRITE' and name = :NEW.name) or (:NEW.typ = 'READ' and name = :NEW.name and typ = 'WRITE');
    if (c > 0) then
        raise_application_error(-20634, 'Nope!');
    end if;
end;

标签: sqloracletriggers

解决方案


触发器在这里对多用户环境没有帮助。您需要序列化对特定锁名称的访问。对于这种情况,我会选择自定义锁。数据库包 dbms_lock 用于此目的。您可以创建一个执行以下操作的函数:

  1. 获取传入名称的自定义锁 - 应使用在提交/回滚时不释放的选项创建此锁
  2. 在表中对名称进行验证
  3. 如果可能(如果验证通过)插入记录并提交它
  4. 释放自定义锁
  5. 返回结果(OK 或 NOK)

希望有帮助。


推荐阅读