【问题标题】:Spring Boot race condition on updating same entity更新同一实体时的 Spring Boot 竞争条件
【发布时间】:2020-08-01 23:43:15
【问题描述】:

对于spring boot,我知道如果我有一个功能说,为了减少用户的平衡,我们可以在服务方法中使用@Transactional注解,如下所示:

@Transactional
public void reduceBalance(long userId, BigDecimal usage) {
    ...
}

但我的问题不是指在特定功能上放置控件,我想知道如下:

public void updateAge(long userId, int newAge) {
    User theUser = userRepository.findById(userId).orElse(null); // Line A-1
    theUser.setAge(newAge); // Line A-2
    userRepository.save(theUser); // Line A-3
}

public void updateName(long userId, String newName) {
    User theUser = userRepository.findById(userId).orElse(null); // Line B-1
    theUser.setName(newName); // Line B-2
    userRepository.save(theUser); // Line B-3
}

假设如果有 2 个请求同时进入,则 A-1 和 B-1 行同时执行,然后是 A-2 和 B-2,然后是 A-3 和 B-3。

B-3 会覆盖 A-2 的更改吗?如果是,是否意味着我们应该在几乎所有服务中都添加@Transactional 注解,或者实际上是否有更好的设计?

【问题讨论】:

    标签: hibernate spring-boot spring-data-jpa


    【解决方案1】:

    强烈建议在每个服务中使用@Transaction,但如果您想通过不同的方式进行管理, 另一种方法是使用@Version 注释

     Specifies the version field or property of an entity class that
     serves as its optimistic lock value.  The version is used to ensure
     integrity when performing the merge operation and for optimistic
     concurrency control.
    

    【讨论】:

    • 感谢您的见解,看来您的个人资料表明您对 Spring Boot JPA 框架有绝对深入的了解,请问您有什么问题吗?所以基于这个问题,B-3 覆盖 A-2 被确认了对吧?如果我们在每个函数中添加@Transactional注解,是否意味着如果A-1后面跟着B-1,B-1会暂停,直到所有A-1~3都执行完?很抱歉问这个问题,因为这些比赛条件似乎太难测试了..
    • 任何时候我都可以测试你的条件,首先因为请求进入控制器,根据定义和默认 Spring 管理任何作为 Singleton 创建的 bean,即所有组件,那么你不应该担心它,因为它会为了到达并且永远不会同时出现两个请求,然后一个请求进入队列,第二个请求也进入队列,他们将按照我提到的那样执行逻辑以便到达。使用静态的东西你可能会担心,总是有问题,那么可以说最后一个会覆盖。
    • 如果你想测试这个场景,同时创建一个压力测试,我可能会推荐使用 Gatling 和 Scala,它很容易创建,你会看到模拟一样很难时间,但是该测试会对其施加压力并放入您的日志中,并在数据库日志中检查结果,以便作为您的应用程序日志。检查时间,如果它们来时您会相差几毫秒。亲切的问候。
    猜你喜欢
    • 2021-11-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-03-19
    • 2017-02-02
    • 1970-01-01
    • 1970-01-01
    • 2018-08-13
    相关资源
    最近更新 更多