应用程序应将每个用户对某个资源的访问限制为每 24 小时的最大访问次数。为了跟踪这些,我们有下表:
CREATE TABLE accesses (
user_id INTEGER NOT NULL,
dt TIMESTAMPZ
);
每次访问资源时,我们都会将其记录在表中。但是,我们还需要检查是否达到了访问限制。为此,我们需要执行以下查询:
SELECT count(*)
FROM accesses
WHERE dt >= timezone('utc', now()) - interval '24 hours' AND user_id = $1
我们需要根据用户限制检查结果。
现在,如果同时请求两个访问,我们可能会遇到问题:
- 如果我们首先读取、比较和插入,我们可能会授予比限制更多的访问权限;
- 如果我们先插入,然后读取和比较,我们可能会禁止合法访问。
我知道的两种方法是使用SERIALIZABLE
事务或SELECT ... FOR UPDATE
. 我不确定后者在这种情况下是否真的有效,因为我们不会更新读取的行,而是插入新的行。所以我认为这将是一个无用的锁,结果可能仍然不正确。
但是,如果有SERIALIZABLE
交易失败,我会重试它。
在这种情况下应该怎么做,以确保适当的访问限制?