java - 不同的线程获得相同的实体并且看不到彼此的变化
问题描述
我有一张桌子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 = true
state 中并且未执行此检查:
if (productInDb != null)
throw new AlreadyActiveException();
我的问题 - 我可以在不在数据库中添加约束的情况下解决这个问题吗?上面的检查没有用吗?
解决方案
您的操作包含 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);
}
推荐阅读
- python - torch.return_types.max 作为张量
- c# - TagLib-Sharp 不编辑评论属性
- laravel - 为什么单击单选按钮时 Laravel Dusk 测试不会触发 x-on:change() 或 x-model
- animation - 理论上你是如何沿着一条路径实现动画的?
- c# - 从身份服务器 url 读取参数
- java - JAVA API 调用 将响应与上一个响应进行比较
- flutter - “字符串”类型不是“描述”类型的子类型
- react-native - 获取父节点句柄 - 类似于 findNodeHandle
- r - 项目和在目录中上升
- django - 将 Selenium Bot 集成到 Django