redis分布式锁

package com.example.redislock.controller;

import org.redisson.Redisson;
import org.redisson.api.RLock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import java.util.UUID;
import java.util.concurrent.TimeUnit;

@Controller
public class IndexController {

@Autowired
private Redisson redisson;


@Autowired
private StringRedisTemplate stringRedisTemplate;


@RequestMapping("test_stock")
@ResponseBody
public String testStock() throws InterruptedException {

String lockKey = "product_001";
String contenId = UUID.randomUUID().toString();

RLock redissonLock = redisson.getLock(lockKey);
try {

// 先確認商品是否存在 1 保證只有一個線程能成功往下執行
// Boolean result = stringRedisTemplate.opsForValue().setIfAbsent("product_001", 100 + "");
// 有效期10s
//stringRedisTemplate.expire("product_001",10, TimeUnit.SECONDS);

// 把上面兩行合并成一行 要麽同時成功要麽同時失敗
Boolean result = stringRedisTemplate.opsForValue().setIfAbsent(lockKey, contenId, 10, TimeUnit.SECONDS);
if (!result) {
return "error商品不存在了";
}

//stringRedisTemplate.opsForValue().set("stock", 100 + "");
System.out.println(stringRedisTemplate.opsForValue().get("stock") + "");

// 多个线程请求到这里 会一个线程拿到锁,其他线程阻塞在这里 while循环一直尝试加锁 // 也有非阻塞的api
redissonLock.lock(30, TimeUnit.SECONDS); // 底层实现就是往Redis里设置一个key value
// 如果加锁成功 会开启一个新线程 给锁续命


int stock = Integer.parseInt(stringRedisTemplate.opsForValue().get("stock"));
if (stock > 0) {

int realStock = stock - 1;
stringRedisTemplate.opsForValue().set("stock", realStock + "");
System.out.println("扣减库存成功===剩余" + stock);
System.out.println("扣减库存成功===剩余" + realStock);

} else {
System.out.println("扣减库存失败===库存不足");
}
} finally {
redissonLock.unlock(); // 释放锁

if (contenId.equals(stringRedisTemplate.opsForValue().get(lockKey))) {
// 釋放鎖
stringRedisTemplate.delete(lockKey);
}
}

return "end";

}


// 全部實行需要 15s
// key 有效期 為10s
// 執行到10s時鎖已經被釋放了
// 第二個綫程 拿到鎖開始執行 黨第一個綫程繼續執行到15s時 八第二個綫程的鎖給釋放了

// 結果鎖永久失效
// 解決給每個綫程生成唯一標識 UUID


// 分佈式鎖的實現
// 拿到鎖 開啓分綫程 定時器每隔一段是按檢查自己加的這把鎖是否存在 每隔3/1 時間重新設置key 的生存時間 續命


// Redisson 底層的實現 也是開啓分綫程的方式

// 主從架構 主節點成功 沒有同步到從節點 沒同步的時候 主節點挂了 選舉新的主節點 這是key 還沒有同步過去呢


}

使用 Redisson 需要初始化Bean
@Configuration
public class RedissonClientConfig {   
  @Value("${spring.redis.host}")  
  private String host;   
@Value("${spring.redis.port}")   
private String port;   
 @Bean   
public RedissonClient getRedisson(){   
     Config config = new Config();     
   config.useSingleServer().setAddress("redis://" + host + ":" + port);     
   return Redisson.create(config);   
}
}


posted @ 2020-02-20 10:51  jack-jin  阅读(144)  评论(0)    收藏  举报