【发布时间】:2015-04-01 20:55:21
【问题描述】:
我有一个用 Java、Spring、Hibernate、Postgres 编写的应用程序。
它跟踪用户的登录尝试。如果用户在 1 小时内对同一 IP 地址进行了超过 5 次无效尝试 - 此 IP 地址将被阻止。
我有以下实体类用于存储有关登录尝试的信息:
@Entity
public class BlockedIp {
private String ipAddress;
private Date blockDate;
private Date unblockDate;
private Date lastAttemptDate;
private Integer wrongAttemptsCount;
...}
首先,当应用收到登录请求时 - 它会检查 IP 地址是否已被阻止(blockDate != null)。然后 in 向用户返回特殊的响应码。
如果应用收到登录请求且凭据错误:
- 如果最后一次尝试不到 1 小时前 - 它会增加 wrongAttemptsCount,如果 (wrongAttemptsCount == 5) - 设置 blockDate。
- 如果上次尝试是在 1 小时前 - 它将 wrongAttemptsCount 设置为 1。
如果应用收到登录请求并且凭据正确 - 它会将 wrongAttemptsCount 重置为零,因此用户最多可以再次犯 5 次错误 :)
问题是当一些用户尝试从同一个 IP 同时登录时。 例如,errorAttemptsCount = 4,因此用户只能进行最后一次尝试。我们有 3 个传入请求,它们都使用了错误的凭据。理论上,只有第一个请求会通过,但另外两个会被阻止。当然,在实践中,all get wrongAttemptsCount 等于 4 从数据库中,所以它们都将作为非阻塞处理。
那么,如果可能的话,我必须使用哪些选项来解决这个问题并且将性能损失降到最低? 我为我的查询考虑了 SELECT FOR UPDATE 语句,但我的同事说这会严重影响性能。 他还提议查看@Version 注释。是不是真的值得吗?是不是快很多? 也许有人可以提供其他选择?
【问题讨论】:
标签: java hibernate postgresql concurrency transactions