Concurrency Spring数据JPA-实体的并发访问

Concurrency Spring数据JPA-实体的并发访问,concurrency,transactions,spring-data,locking,spring-data-jpa,Concurrency,Transactions,Spring Data,Locking,Spring Data Jpa,我想确保只有1个线程可以访问我的服务函数中的实体。怎么做 示例:我希望安全地减少计数:即使多个线程执行OrderService.remove(产品),我也不希望使用相同的计数器值进行2次DB更新 在多线程环境中,2个线程可以同时执行此函数,它们可以读取相同的计数器值,因此使用相同的减少值更新数据库。这是不可取的 产品: @Entity public class Product { @Id @GeneratedValue private UUID id; pri

我想确保只有1个线程可以访问我的服务函数中的实体。怎么做

示例:我希望安全地减少计数:即使多个线程执行OrderService.remove(产品),我也不希望使用相同的计数器值进行2次DB更新

在多线程环境中,2个线程可以同时执行此函数,它们可以读取相同的计数器值,因此使用相同的减少值更新数据库。这是不可取的

产品:

@Entity
public class Product {

    @Id
    @GeneratedValue
    private UUID id;

    private Integer count;

    ...
产品服务:

@Service
@Transactional
public class ProductService {

    public void remove(UUID productId) {

        final Product product = productRepository.findById(productId);

        // TODO how to lock product, so no other thread can modify it before this operation is committed?
        final Integer currentCount = product.getCount();
        product.setCount(currentCount-1);

    }

}
您希望
将(…)
方法作为事务工作(这样就不会使用此方法对数据库进行并发更新)。为此,应将该方法标记为
@Transactional

只要可串行化保证并发事务的效果等同于它们的串行(即顺序)执行,就可以将隔离级别显式设置为
隔离。可串行化
就足够了

@Transactional(isolation = Isolation.SERIALIZABLE)
public void remove(UUID productId) {
    ...
}
如果在处理事务时需要更多高级逻辑,可以使用较低的隔离级别并重试策略:
@Retryable(StaleStateException.class)


有关详细信息,请参见。

能否澄清您的问题?您希望对“Product.count”字段进行线程安全修改,还是希望进行事务性数据库更新?我更新了我的问题。然后更新了答案。如果我没有指定隔离级别并且没有设置重试策略,则在发生冲突的事务时会发生什么情况?只有一个事务成功吗?数据库将为您执行所有锁定。如果两个事务(您的
remove()
方法)试图访问相同的数据,其中一个事务将被迫等待,直到另一个事务完成。这两个事务将按第一个事务执行,另一个事务在第一个事务完成后到达。我知道如果设置了隔离=隔离.SERLIALIZE,情况就是这样,但是如果隔离级别更宽松,会发生什么?(例如,默认值)使用其他隔离级别,您将获得它们为您提供的确切保证。例如,您可以看到本教程:默认隔离级别的行为因数据库而异。例如,在Postgres中,它被读取为提交: