Java Postgres中嵌套SELECT子句的原子更新

Java Postgres中嵌套SELECT子句的原子更新,java,spring,postgresql,jpa,transaction-isolation,Java,Spring,Postgresql,Jpa,Transaction Isolation,我有一个集群,其中一个节点是主节点。通过数据库(Postgres通过java/spring/jpa访问)完成谁将成为新主人的同步/决策 这是我目前拥有的 @Repository public interface ServiceRepository{ @Transactional @Modifying @Query("UPDATE ServiceInstance e SET e.master=true" + " where e.id=:servic

我有一个集群,其中一个节点是主节点。通过数据库(Postgres通过java/spring/jpa访问)完成谁将成为新主人的同步/决策

这是我目前拥有的

@Repository
public interface ServiceRepository{


@Transactional
@Modifying
@Query("UPDATE ServiceInstance e SET e.master=true"
        + " where e.id=:serviceId AND NOT"
        + " EXISTS (SELECT master from ServiceInstance where master = true)")
int tryToBecomeMaster(@Param("serviceId") String serviceId);
对于集群中的每个节点,数据库中有一行ServiceInstance。每个节点都试图更新自己的行,但仅当没有行已标记为“主”时。每个节点定期运行该查询

那个查询是原子的还是存在竞争条件?如果它不是原子的,我在这里需要什么事务隔离级别


我主要担心的是,如果允许并行执行两个查询,它们可能会将SELECT子句计算为false(无主控)并更新它们的行。

如果要确保不能并行读取您的
SELECT
子句,您可以使用带有聚合功能的
SELECT FOR UPDATE
,而不是
WHERE
子句来检测主机;这将自动锁定表中的所有行,直到更新完成

另一种方法是手动执行
锁表独占
命令


在您的情况下,两者都应该正常工作。

要确保只能有一个主节点,请在表上创建唯一的部分索引:

CREATE UNIQUE INDEX ON serviceinstance ((1)) WHERE master;
当您尝试将表中多行的
master
设置为
TRUE
时,这将给您一个错误,ACID的C保证(一致性)将确保这始终有效。您必须捕获并处理函数中的异常


请允许我指出,这不是实现高可用性集群的好方法:它在数据库的形状上有一个单点故障。

Postgresql事务始终与ACID兼容。A的意思是原子。是的,是这样。选择更新没有多大意义,因为这两个并发事务将看不到任何主数据,所以选择将返回(并锁定)0行,然后将继续更新2个不同的行。我建议在“选择更新”中使用聚合函数,而不是在“位置”中使用聚合函数,以便在所有行上正确锁定。这很有效,谢谢!