如何解决Postgres 中带有嵌套 SELECT 子句的原子更新
我有一个集群,其中一个节点是主节点。通过数据库(通过java/spring/jpa访问Postgres)完成同步/决定谁将成为新的master。
这是我目前拥有的
@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);
对于集群中的每个节点,DB 中都有一行 ServiceInstance。每个节点都试图更新自己的行,但前提是没有行已标记为“主”。该查询由每个节点定期运行。
该查询是原子还是存在竞争条件?如果它不是原子的,我在这里需要什么事务隔离级别?
我主要担心的是,如果允许并行执行 2 个查询,它们可能会将 SELECT 子句计算为 false(无主)并更新它们的行。
解决方法
为了确保只能有一个 master,在表上创建一个唯一的部分索引:
CREATE UNIQUE INDEX ON serviceinstance ((1)) WHERE master;
一旦您尝试将表中多于一行的 master
设置为 TRUE
,这将给您一个错误,并且 ACID 保证(一致性)的 C 将确保这总是有效的。您必须在函数中捕获并处理异常。
我要指出,这不是实现高可用性集群的好方法:它具有数据库形式的单点故障。
,如果你想确保你的 SELECT
子句不能被并行读取,你可以使用带有聚合函数的 SELECT FOR UPDATE
来检测 master 而不是 WHERE
子句;这将自动锁定表的所有行,直到 UPDATE
完成。
另一种方法是手动执行 LOCK TABLE EXCLUSIVE
命令。
两者都应该在您的情况下正常工作。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。