一、利用Redis实现分布式锁
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/deduct_stock")
public String deductStock(){
String lockKey = "product_101";
//Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,"zhuge"); //jedis.setnx(k, v)//①
//stringRedisTemplate.expire (lockKey,10,TimeUnit.SECONDs); //②
String clientID=UUID.randomUUID().toString();
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey,clientID,10,TimeUnit.SECONDs);//③
if (!result){
return "error_code";
try {//④
int stock = Integer. parseInt(stringRedisTemplate.opsForValue().get(" stock"));//jiedis. get("stock")
if (stock > 0){
int realStock = stock - 1;
stringRedisTemplate.opsForValue ().set("stock", realStock + "");// jedis.set(key, value)
System.out.println("扣减成功,剩余库存:" + realStock);
}else {
System.out.println("扣减失败,库存不足");
}
}finally {//⑤
if(clientID.equals(stringRedisTemplate.opsForValue ().get(lockKey))){
stringRedisTemplate.delete(lockKey);//⑥
}
}
return "end" ;
}
①运用Spring封装的Redis方法,setIfAbsent(lockKey,v: “zhuge”),将"zhuge"赋给lockKey
②为运行过程中可能出现线程宕机,为该值设置一个过期时间,防止该值无法被释放导致后续的新请求失败
③为了保证原子性,将两个代码合成一句,即创建出key-value时直接给与过期时间
④对主程序进行try操作,若主程序执行过程中出现问题,确保定义的Key-Value值能被释放
⑤finally保证每次用完之后使Key-Value值释放
⑥运行结束后释放分布式锁
在Redis中,
SETNX
格式: setnx key value
将key的值设为 value ,当且仅当key不存在。若给定的 key 已经存在,则SETNX不做任何动作。
SETNX是『SET if Not exists』(如果不存在,则SET)的简写。例如
set qyx 18
set qyx 22 执行结果为qyx-22
setnx qyx 18
setnx qyx 22 执行结果为qyx-18,即当使用setnx时,若检测到key存在,则对value不做任何改变,因此可以实现分布式锁。
二、redisson
redisson是Redis的客户端技术,与jedis类似
引用相依赖包
<dependency>
<groupId>org.redisFon</groupId>
<artifactId>redisson</artifactId>
<version>3.6.5</version>
</dependency>
配置相关参数
@SpringBootApplication
public class Application{
public static void main(String[] args){ SpringApplication.run(Application.class,args);}
@Bean//放到容器中
public Redisson redisson(){
//此为单机模式
Config config = new Config ;
config.useSingleServer().setAddress("redis://localhost:6379").setDatabase(0);//端口号和调用的数据库
return (Redisson) Redisson.create(config);
}
}
使用
@Autowired
private Redisson redisson;//将redisson注入
@Autowired
private StringRedisTemplate stringRedisTemplate;
@RequestMapping("/deduct_stock")
public String deductStock(){
String lockKey = "product_101";
RLock redissonLock = redisson.getLock(lockKey);
try {//④
redissonLock.lock();//主程序加锁
int stock = Integer. parseInt(stringRedisTemplate.opsForValue().get(" stock"));//jiedis. get("stock")
if (stock > 0){
int realStock = stock - 1;
stringRedisTemplate.opsForValue ().set("stock", realStock + "");// jedis.set(key, value)
System.out.println("扣减成功,剩余库存:" + realStock);
}else {
System.out.println("扣减失败,库存不足");
}
}finally {//⑤
redissonLock.unlock();//释放锁
}
return "end" ;
}