【问题标题】:Concurrent entities read/update with Hibernate and Postgres使用 Hibernate 和 Postgres 读取/更新并发实体
【发布时间】: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


    【解决方案1】:

    乐观锁定产生最好的性能和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 阻止了这种情况,但增加事务隔离级别确实会降低您的应用程序可扩展性。

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

    【讨论】:

    • 让我们总结一下。就我的问题而言,我应该:1)使用Version注释(为此在我的实体中引入一些特殊字段),2)在保存\更新此实体的所有方法中捕获StaleStateException,3)如果发生此类异常- 再次检索实体以获取其新状态并重复我算法的所有步骤。我说的对吗?
    • 你是对的。第 3 步应该在新的事务/会话中运行。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2017-08-14
    • 1970-01-01
    • 2021-10-15
    • 2012-01-25
    • 2017-10-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多