考虑情况:java是个多线程机制。多线程是一把双刃剑,一旦设计到多个线程操作共享资源的情况下,处理不好就会出现线程安全问题。线程安全性可能是非常复杂的,在沒有充足的同步情况下,多个线程执行顺序是不好操作的。
同步和异步: 同步就是一件事,一件事情一件事的做。异步就是,做一件事情,不引响做其他事情。
应用场景:用户下订单的时候考虑到并发情况。商品购买是有库存的,一个用户可以购买商品数量为多个,如多个用户同时下单可能会产生商品不够,但订单生成成功问题。
解决办法:采用乐观锁解决,商品表中添加一个冻结数量字段和一个数据版本字段
下订单之前先获取当前商品信息。
加锁:
// 查询当前商品信息
// 【乐观锁】获取版本
ULCommodityTg dbCommodityTg = ulCommodityTGDao.selectById(orderSubmitPO.getCommodityId());
if (dbCommodityTg == null) {
bo.setOrderInfo(ULApiResultTips.Order.ORDER_ERROR);
return new ULResult<CResultOrderInfoBO>(bo);
}
boolean flag = false;
for (int i = 0; i < 3; i++) {
// 使用当前数据版本,追加冻结数量
Integer happyLock = ulCommodityTGDao.updateByHappyLock(dbCommodityTg.getId(),
dbCommodityTg.getDataVersion(), orderSubmitPO.getQuantity());
if (happyLock > 0) {
flag = true;
break;
}
Thread.sleep(1000);
// 重新获取版本,再次尝试下单
dbCommodityTg = ulCommodityTGDao.selectById(orderSubmitPO.getCommodityId());
}
// 数据版本已增加,当前订单更新失败
if (!flag) {
bo.setOrderInfo(ULApiResultTips.Order.ORDER_OVERFLOW);
return new ULResult<CResultOrderInfoBO>(bo);
}
根据版本号判断当前下单用户。
解锁:
ULShop dbShop = ulShopDao.selectById(dbOrder.getShopId());
// 商铺销售量加一
dbShop.setSalesVolume(dbShop.getSalesVolume() + 1);
dbShop.setUpdateTime(now);
ulShopDao.updateByPrimaryKeySelective(dbShop);
// 团购 美食
if (ULOrderJumpTypeEmun.TG_FOOD.getType().equals(dbOrder.getJumpType())) {
// 加销量、减冻结数量
List<ULOrderFood> dbFoods = ulOrderFoodDao.selectByProperty("orderNo", orderNo);
ULCommodityTg dbCommodity = ulCommodityTGDao.selectById(dbFoods.get(0).getCommodityId());
dbCommodity.setSalesFreeze(dbCommodity.getSalesFreeze() - dbOrder.getQuantity());
dbCommodity.setSalesQuantity(dbCommodity.getSalesQuantity() + dbOrder.getQuantity());
// 添加销量
dbCommodity.setSalesQuantity(dbCommodity.getSalesQuantity() + dbFoods.size());
dbCommodity.setUpdateTime(now);
ulCommodityTGDao.updateByPrimaryKeySelective(dbCommodity);
}
至此:乐观锁添加完成,保证了用户购买的数量不能超过当前库存。