插入和相应的触发器是原子过程吗?

时间:2019-01-11 11:30:36

标签: sql oracle triggers

我有一个名为LOCK的表,我想确保不多于一个具有给定名称和类型WRITE的行。尽管允许多行类型为READ且名称相同的行,但前提是不存在名称相同且类型为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;

1 个答案:

答案 0 :(得分:1)

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

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

希望有帮助。