首页 > 解决方案 > 不同的线程获得相同的实体并且看不到彼此的变化

问题描述

我有一张桌子products。在这张表中,我需要is_active约束 -only one row with the same type can be true.

Product我有通过检查保存新的服务:

@Service
public class ProductServiceImpl implements ProductService {

    private final ProductRepository productRepository;

    public ProductServiceImpl(ProductRepository productRepository) {
        this.productRepository = productRepository;
    }

    @Override
    public void save(Product product) {

        Product productInDb = productRepository.findOneByTypeAndIsActive(product.getType());

        if (productInDb != null)
            throw new AlreadyActiveException();

        product.setActive(true);
        productRepository.saveAndFlush(product);
    }
}

当我save在几个线程中调用方法并尝试检查活动产品时 - 在两个线程中findOneByTypeAndIsActive方法都会返回productInDb is null,因为我在表中没有活动产品。product.setActive(true);在我设置并尝试保存在数据库中的每个线程中。如果我在 DB 中没有约束 - 我将两个产品都保存在is_active = truestate 中并且未执行此检查:

     if (productInDb != null)
        throw new AlreadyActiveException();

我的问题 - 我可以在不在数据库中添加约束的情况下解决这个问题吗?上面的检查没有用吗?

标签: javamultithreadinghibernatejpaspring-data-jpa

解决方案


您的操作包含 2 个操作:

  1. 从数据库中获取实体

  2. 如果新实体不存在,则保存它

您的问题是很少有线程可以同时启动此操作并且看不到彼此的变化。这绝对不是你需要的。您的操作由几个动作组成,必须是原子的。

如果我理解正确,您的规则是在数据存储中只保留 1active个相同的产品type。这听起来像是一个数据一致性要求,应该在应用程序级别解决。

解决您的问题的最幼稚的选择是在执行操作之前获取锁。它可以通过使用synchronised或显式锁定来解决:

@Override
public synchronised void save(Product product) {

    Product productInDb = productRepository.findOneByTypeAndIsActive(product.getType());

    if (productInDb != null)
        throw new AlreadyActiveException();

    product.setActive(true);
    productRepository.saveAndFlush(product);
}

推荐阅读