使用redis的setnx命令放入数据并用此数据当锁完成业务(但是如果用户操作途中出现异常导致超出指定时间会出现问题)
@Service
public class StockService {
@Autowired
private StockDao stockDao; //mapper注入
@Autowired
private StringRedisTemplate redisTemplate; //使用redis方法
//
public String decrement(Integer productid) {
ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
//1.获取共享锁资源(通过进行redis放入数据的方式,如果放入成功说明redis没有该数据)
Boolean flag = opsForValue.setIfAbsent("product::" + productid, "1111", 30, TimeUnit.SECONDS);
//表示获取锁成功
if(flag) {
try {
//根据id查询商品的库存
int num = stockDao.findById(productid);
if (num > 0) {
//修改库存
stockDao.update(productid);
System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个");
return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个";
} else {
System.out.println("商品编号为:" + productid + "的商品库存不足。");
return "商品编号为:" + productid + "的商品库存不足。";
}
}finally {
//释放锁资源(删除放入的该数据,然后准备开始下一次抢锁)
redisTemplate.delete("product::"+productid);
}
}else{
//休眠100毫秒 在继续抢锁
try {
Thread.sleep(100);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return decrement(productid);
}
}
}
看门狗(改善版,解决了超时的bug)
引入依赖
<dependency> <groupId>org.redisson</groupId> <artifactId>redisson</artifactId> <version>3.24.3</version> </dependency>
编写配置类
@Configuration public class RedissonConfig { @Bean public RedissonClient redisson(){ Config config = new Config(); //连接redis集群 config.useClusterServers() use "rediss://" for SSL connection .addNodeAddress("redis://127.0.0.1:7181","","",""); //连接单机 config.useSingleServer().setAddress("redis://192.168.111.188:6379"); RedissonClient redisson = Redisson.create(config); return redisson; } }
业务代码
@Service public class StockService { @Autowired private StockDao stockDao; //注入mapper @Autowired private RedissonClient redisson; //注入看门狗 // public String decrement(Integer productid) { RLock lock = redisson.getLock("product::" + productid); //获取锁资源 lock.lock(); //上锁 try { //根据id查询商品的库存: 提前预热到redis缓存中 int num = stockDao.findById(productid); if (num > 0) { //修改库存---incr---定时器[redis 数据库同步] stockDao.update(productid); System.out.println("商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个"); return "商品编号为:" + productid + "的商品库存剩余:" + (num - 1) + "个"; } else { System.out.println("商品编号为:" + productid + "的商品库存不足。"); return "商品编号为:" + productid + "的商品库存不足。"; } }finally { lock.unlock(); //释放锁资源 } } }