对于 PostgreSQL 表,我想锁定特定行以防止将来编辑。这是签署审核数据过程的一部分。
从文档和其他线程来看,与锁定有关的所有内容都与在其他数据库进程运行时临时锁定行有关。但是我想阻止用户无限期地修改已审核的数据。
有人有这方面的经验或想法吗?
行级安全策略可以做到这一点:db<>fiddle
演示create table test (
id int generated by default as identity primary key,
payload text,
is_locked boolean default false);
insert into test values
(default,'Auditing is due to review this one.',default)
,(default,'We are waiting for legal to sign off on this.',false)
,(default,'This one passed audit and is locked.',true);
create role mc_hammer;
grant usage on schema public to mc_hammer;
alter table test enable row level security;
create policy can_see_this on test for select
to mc_hammer using (true);
create policy cant_touch_this_i on test for insert
to mc_hammer with check (not is_locked);
create policy cant_touch_this_u on test for update
to mc_hammer using (not is_locked)
with check (not is_locked);
create policy cant_touch_this_d on test for delete
to mc_hammer using (not is_locked);
grant select,insert,update,delete,references,trigger on test to mc_hammer;
现在用户
mc_hammer
可以修改is_locked=false
所在的行,例如行1
:
set role mc_hammer;
update test
set payload=current_user||' touched this '||now()::text
where id=1
returning *;
id | 有效负载 | 已锁定 |
---|---|---|
1 | mc_hammer 触及了这个 2024-06-14 10:18:06.844776+00 | f |
但是第
3
行被锁定,因此他们无法 update
或 delete
它。使用 insert..on conflict do update
或 merge
进行插入也不起作用。他们也无法insert
已经锁定的行。它只是不起作用,没有抛出错误:
update test
set payload=current_user||' touched this '||now()::text
where id=3
returning *;
id | 有效负载 | 已锁定 |
---|
UPDATE 0
set role postgres;
select * from test;
id | 有效负载 | 已锁定 |
---|---|---|
2 | 我们正在等待法律部门对此的批准。 | f |
3 | 此已通过审核并已锁定。 | t |
1 | mc_hammer 触及了这个 2024-06-14 10:18:06.844776+00 | f |
mc_hammer
尝试同时触摸1
和3
,但它只对1
有效,因为3
已被锁定。