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

时间:2018-04-28 18:49:04

标签: concurrency transactions spring-data locking spring-data-jpa

我想确保只有一个线程可以访问我的服务功能中的实体。怎么做?

示例:我想安全地减少计数:即使多个线程执行OrderService.remove(Product),我也不希望2个DB更新具有相同的计数器值。

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

产品:

@Entity
public class Product {

    @Id
    @GeneratedValue
    private UUID id;

    private Integer count;

    ...

ProductService:

@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);

    }

}

1 个答案:

答案 0 :(得分:1)

您希望remove(..)方法工作作为交易(因此,使用此方法无法对数据库进行并发更新) 。为此,您应将方法标记为@Transactional 只要可序列化保证并发事务的影响等同于它们的串行(即顺序)执行,将显式隔离级别明确设置为Isolation.SERIALIZABLE就足够了。

@Transactional(isolation = Isolation.SERIALIZABLE)
public void remove(UUID productId) {
    ...
}

如果在处理交易时需要更多高级逻辑,则可以使用较低的隔离级别并重试策略:@Retryable(StaleStateException.class)
有关详细信息,请参阅https://github.com/spring-projects/spring-retry