PostgresQL如何在可空的外部连接列上实现悲观锁定

y0u0uwnf  于 2023-10-18  发布在  PostgreSQL
关注(0)|答案(1)|浏览(155)

我试图在一个复杂的实体上实现悲观锁定,但是Postgres不支持SELECT FOR UPDATE和OUTER JOIN空字段。是否有变通办法?
范例:

create table A(
  id serial primary key,
  name character varying(20) not null
);

create table B(
  id serial primary key,
  a_id int references a(id) on delete cascade not null,
  name character varying(20) not null
);

create table C(
  id serial primary key,
  b_id int references b(id) on delete cascade not null,
  name character varying(20) not null
);

// Query:
SELECT *
FROM A
  LEFT JOIN B ON A.id = B.a_id
  LEFT JOIN C ON B.id = C.b_id
WHERE A.id = 5;

我需要一种方法来执行这样的查询,锁定表a,b和c中的行进行更新。此外,我需要锁定插入表B和C中的行,即选定行上的引用。

SELECT *
FROM A
  LEFT JOIN B ON A.id = B.a_id
  LEFT JOIN C ON B.id = C.b_id
WHERE A.id = 5
FOR UPDATE; <<---- DOES NOT WORK IN POSTGRES

现在我明白了,唯一的方法是做3个SELECT语句,从表A、B和C中选择行进行更新,并在应用程序端连接它们,但这种方式似乎比在数据库端连接慢。
有没有办法在数据库中执行JOIN,锁定所有选定的行?

t40tm48m

t40tm48m1#

在PostgreSQL中,查询不可能强制执行悲观锁定,因为PostgreSQL不接受任何表提示,也不接受查询的任何部分中的任何提示,如Micosoft SQL Server,Oracle数据库或任何其他RDBMS(您必须通过购买企业版来支付)。
您唯一能做的就是编写一个SQL脚本或PF“函数”作为一个过程,在该过程中,您将显式地锁定显式事务中的表。
例如:

BEGIN WORK;
LOCK TABLE A IN ROW EXCLUSIVE;
LOCK TABLE B IN ROW EXCLUSIVE;
LOCK TABLE C IN ROW EXCLUSIVE;

SELECT *
FROM A
  LEFT JOIN B ON A.id = B.a_id
  LEFT JOIN C ON B.id = C.b_id
WHERE A.id = 5

...

COMMIT WORK;

这不是PG唯一不能做的事情,看看这篇论文:“PostgreSQL vs. SQL Server (MSSQL) – part 3 – Very Extremely Detailed Comparison

相关问题