如果扣减库存的操作在一台机器上
使用本地锁
JVM 锁
不和数据库交互,模拟库存扣减。并发测试 100 个线程,访问50次。
private void jvmLock() {
lock.lock();
try {
goods.setInventory(goods.getInventory()-1);
log.info(goods.getInventory().toString());
}finally {
lock.unlock();
}
}
不加锁出现并发问题,因为扣减和 set 不是原子操作,多个线程几乎同时拿到变量,多次扣减其实只减了一次。
用 voliate 能解决问题吗?不能,不保证原子性。
private void mysqlLock() {
CommerceGoods good = goodsMapper.selectOne(Wrappers.lambdaQuery(CommerceGoods.class)
.eq(CommerceGoods::getGoodsName, "lock-test")
.select()
);
good.setInventory(good.getInventory()-1);
goodsMapper.updateById(good);
log.info(good.getInventory().toString());
}
毫无疑问,同样会出现超卖现象。加锁解决,这是肉眼可见的并发量和吞吐量下降。
for udpate 悲观锁
select * from table where name = productName for update;
直接修改
update table set inventory = (inventory - 1) where id = 1 ;
Redis 原子操作
不加锁就不会出现超卖,而且吞吐量很高。
private void redisAtomic() {
redisTemplate.opsForValue().decrement("lock-test");
log.info(Objects.requireNonNull(redisTemplate.opsForValue().get("lock-test")).toString());
}
CAS 乐观锁
update table set surplus = newQuantity where id = 1 and surplus = oldQuantity ;
private void casLock() {
int result = 0;
while (result==0){
CommerceGoods good = goodsMapper.selectOne(Wrappers.lambdaQuery(CommerceGoods.class)
.eq(CommerceGoods::getGoodsName, "lock-test")
.select());
Long inventory = good.getInventory();
good.setInventory(good.getInventory()-1);
result = goodsMapper.update(good,Wrappers.lambdaUpdate(CommerceGoods.class)
.eq(CommerceGoods::getInventory,inventory));
}
}
如果扣减库存的操作在多台机器上
标签:场景,CommerceGoods,扣减,lock,good,getInventory,设计,超卖 From: https://www.cnblogs.com/DCFV/p/18355915分布式锁