redis分布式锁
redis分布式锁
使用分布式锁的原因
普通锁场景:
@Service
public class StockService02 {
@Resource
private StockDao stockDao;
//查询对应的id的库存方法
public String decrStock(Integer productId) {//synchronized () 同步方法 同步代码块
//查询对应的id的库存
synchronized (this) {
Stock stock = stockDao.selectById(productId);
if (stock.getNum() > 0) {
//根据id修改库存
stock.setNum(stock.getNum() - 1);
stockDao.updateById(stock);
System.out.println("库存剩余:" + (stock.getNum()));
return "库存减少成功";
} else {
return "库存不足";
}
}
}
}
这种锁不适合分布式项目。因为同步锁只能在同一个项目中起作用。
这时我们通过使用redis中的setNX方法来达到分布式锁
使用redis解决分布式锁的问题
@Service
public class StockService {
@Resource
private StockDao stockDao;
@Autowired
private StringRedisTemplate redisTemplate;
public String decrStock(Integer productId) {//synchronized () 同步方法 同步代码块
//redisTemplate.opsForValue().setIfAbsent("product::" + productId, "ykq",30, TimeUnit.SECONDS);
// 设置以product::" + productId此唯一标识为key 设置存活时间
Boolean flag = redisTemplate.opsForValue().setIfAbsent("product::" + productId, "ykq",30, TimeUnit.SECONDS);
//查询对应的id的库存
if(flag) {//获取锁了
try {
Stock stock = stockDao.selectById(productId);
if (stock.getNum() > 0) {
//根据id修改库存
stock.setNum(stock.getNum() - 1);
stockDao.updateById(stock);
System.out.println("库存剩余:" + (stock.getNum()));
return "库存减少成功";
} else {
return "库存不足";
}
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}
finally {
redisTemplate.delete("product::" + productId);//释放锁资源 一定再finally
}
}else{
System.out.println("服务器正忙请稍后再试..........");
return "服务器正忙请稍后再试..........";
}
}
}
使用第三方组件redisson-----专门用于解决分布式问题。
依赖
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.13.4</version>
</dependency>
配置类
@Bean
public RedissonClient getRedisson(){
Config config=new Config();
config.useSingleServer().setAddress("redis://192.168.213.188:6379");
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
java代码
@Service
public class StockService {
@Resource
private StockDao stockDao;
@Autowired
private RedissonClient redisson;
public String decrStock(Integer productId) {//synchronized () 同步方法 同步代码块
RLock lock = redisson.getLock("product::" + productId);//获取锁对象
try {
lock.tryLock(60,20,TimeUnit.SECONDS); //自己别设置时间。
Stock stock = stockDao.selectById(productId);
if (stock.getNum() > 0) {
//根据id修改库存
stock.setNum(stock.getNum() - 1);
stockDao.updateById(stock); //异常发生
// int c=10/0;
// Thread.sleep(35000);
System.out.println("库存剩余:" + (stock.getNum()));
return "库存减少成功";
} else {
return "库存不足";
}
}catch (Exception e){
throw new RuntimeException(e.getMessage());
}
finally {
lock.unlock();
}
}
}