【发布时间】:2021-12-12 21:20:13
【问题描述】:
如何避免两个用户同时结账,但没有足够的产品供他们使用? 用户有一篮子商品,结账时,店内商品数量应减少
@Transactional(isolation = Isolation.READ_COMMITTED, propagation = Propagation.REQUIRES_NEW)
public boolean createOrder(User user) {
if (!cartRecordService.checkAvailable()) {
return false;
}
final Map<Long, Long> records = cartRecords.getRecords();
Long sum = 0L;
for (Long id : records.keySet()) {
Goods goods = goodsRepository.findById(id).get();
sum += goods.getPrice() * records.get(id);
}
Date dateNow = new Date();
Order order = new Order(dateNow, sum, true, user);
orderRepository.save(order);
Order lastUsersOrder = orderRepository.findByUserOrderByIdDesc(user).get(0);
for (Long id : records.keySet()) {
Goods goods = goodsRepository.findById(id).get();
goods.setAvailable(goods.getAvailable() - records.get(id));
goodsRepository.save(goods);
addOrderGoods(new OrderGoods(goods, lastUsersOrder, records.get(id)));
}
return true;
}
@Transactional(propagation = Propagation.MANDATORY)
public void addOrderGoods(OrderGoods orderGoods){
orderGoodsRepository.save(orderGoods);
}
@Transactional(propagation = Propagation.REQUIRED, isolation = Isolation.REPEATABLE_READ)
public boolean enoughQuantity(CartAdditionDTO cartAdditionDTO){
Long available = goodsRepository.getById(cartAdditionDTO.getId()).getAvailable();
return available >= cartAdditionDTO.getQuantity();
}
@Transactional(propagation = Propagation.MANDATORY, isolation = Isolation.READ_COMMITTED)
public boolean checkAvailable(){
final Map<Long, Long> records = cartRecords.getRecords();
for(Long id : records.keySet()){
if(!goodsService.enoughQuantity(new CartAdditionDTO(id, records.get(id)))){
return false;
}
}
return true;
}
试图对事务的隔离做一些事情,但它不起作用
【问题讨论】:
-
您需要执行
SELECT ... FOR UPDATE的 ORM 等效项来锁定行,直到其中一个事务完成。仅使用REPEATABLE READ事务隔离级别(InnoDB 默认)是不够的。
标签: java database multithreading spring-boot transactions