在 Postgres 数据库中,我的关系如下:
- Group 表有一个列 userEntranceLimits。
- UserEntrance 表有一个列 userId 和一个列 groupId。
- 特定组的 UserEntrance 的不同用户的计数不得超过组的 userEntranceLimits。
- 在用于创建新 UserEntrance 的事务(其隔离级别为 REPEATABLE_READ)内部,我检查该组的当前 UserEntrance 计数是否 >= 限制。
- 如果不是,我继续创建一个新的 UserEntrance。
- 在极少数情况下,组出现的 UserEntrance 数超过其限制。
我理解为什么存在这种竞争条件,但我不明白在不使用 SERIALIZABLE 隔离级别的情况下防止它发生的正确方法。我们在这张表上有很多并发写入,当我们之前尝试使事务 SERIALIZABLE 时,它并不顺利。
我现在的想法是做一个SELECT ... FOR UPDATE
并计算应用程序端的出现次数,但这对我来说似乎是一个糟糕的解决方案。这种问题的正确解决方案是什么?
SELECT ... FOR UPDATE 在这种情况下将不起作用。它仍然需要 SERIALIZABLE 隔离级别,因为您需要做的是防止其他会话插入具有相同 groupId 的行。为此,您需要锁定一个键(实际上是 SERIALIZABLE 级别所做的)。你可以尝试做什么?: