gpt4 book ai didi

java - 使用 Hibernate 和 Postgres 读取/更新并发实体

转载 作者:行者123 更新时间:2023-11-29 13:28:16 26 4
gpt4 key购买 nike

我有一个用 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)。然后返回特殊的响应码给用户。

如果应用收到登录请求并且凭据错误:

  • 如果上次尝试不到 1 小时前 - 它会增加 wrongAttemptsCount,如果 (wrongAttemptsCount == 5) - 设置 blockDate。
  • 如果上次尝试是在 1 小时前 - 它会将 wrongAttemptsCount 设置为 1。

如果应用收到登录请求且凭据正确 - 它会将 wrongAttemptsCount 重置为零,因此用户最多可以再次犯 5 次错误:)

问题是当一些用户尝试从同一个 IP 同时登录时。例如,wrongAttemptsCount = 4,因此用户只能进行最后一次尝试。我们有 3 个传入请求,它们都使用了错误的凭据。理论上,只有第一个请求会通过,但另外两个请求会被阻止。实际上,当然,所有从数据库中获取的wrongAttemptsCount都等于4,所以它们都将被处理为非阻塞。

那么,如果可能的话,我有哪些选择可以解决这个问题并且性能损失最小?我考虑过为我的查询使用 SELECT FOR UPDATE 语句,但我的同事说这会严重影响性能。他还提出要查​​看@Version 注释。是不是真的值得吗?是不是快多了?也许有人可以提供其他选择?

最佳答案

乐观锁定产生最好的性能,也是 prevents lost updates in multi-request conversations , 它将防止多个并发事务在未收到有关新行版本的通知的情况下更新同一行。

只有一项交易会通过,其他交易会出现陈旧状态异常。你必须明白 locks are acquired even if you don't explicitly request it so .每个修改的行都需要一个锁,只是 transactional write-behind cache将实体状态转换推迟到当前事务的末尾。

SELECT FOR UPDATE,与任何 pessimistic locking mechanism 一样需要显式锁。您还可以使用 PESSIMISTIC_READ 获取共享锁,因为 PostgreSQL 也支持它。

PESSIMISTIC_READ 将阻止其他事务获取您的 User 实体上的共享锁,但如果没有乐观锁定,您仍然可以有 5 次以上的失败尝试。当前事务释放锁后,其他竞争事务将获取新释放的锁并保存新的失败逻辑尝试。这发生在 READ_COMMITTED 但被 REPEATABLE_READ or SERIALIZABLE 阻止了,但提高事务隔离级别确实会降低应用程序的可扩展性。

总而言之,使用乐观锁定并相应地处理陈旧状态异常。

关于java - 使用 Hibernate 和 Postgres 读取/更新并发实体,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/29400633/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com