sql - 插入和相应的触发器调用是原子过程吗?
问题描述
我有一个名为的表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;
解决方案
触发器在这里对多用户环境没有帮助。您需要序列化对特定锁名称的访问。对于这种情况,我会选择自定义锁。数据库包 dbms_lock 用于此目的。您可以创建一个执行以下操作的函数:
- 获取传入名称的自定义锁 - 应使用在提交/回滚时不释放的选项创建此锁
- 在表中对名称进行验证
- 如果可能(如果验证通过)插入记录并提交它
- 释放自定义锁
- 返回结果(OK 或 NOK)
希望有帮助。
推荐阅读
- storage - 重命名 App Inventor 项目会清除 TinyDB 吗?
- php - 限制树枝循环
- python - 如何确定在 SLURM 中超出 python 脚本步骤内存的哪个点
- spring-mvc - 将 SSO 与具有本机身份验证的应用程序集成
- javascript - 在Vue中单击路由器链接上的激活方法
- c++ - 当 C++/11 auto 关键字更有效或总是按值传递时,是否将参数推导出为按引用传递?
- python - 根据其他多个条件获取列值
- apache-spark - Apache Spark 错误无法找到或加载主类 C:\spark\jars\aircompressor-0.8.jar
- java - REST webservice call for HTTPS link - 400 Bad Request error
- r - 识别R中两列中的对