redis的分布式锁核心在 setnx 方法,成功返回1,失败返回0
案例:搭建springboot集成redis实现分布式锁,100个线程同时生产订单号场景
思路:
1,获取锁,成功执行第2步,失败就等待获取锁成功
2,执行业务
3,释放锁
1,pom文件
org.springframework.boot
spring-boot-starter-web
2.6.2
org.springframework.boot
spring-boot-starter-data-redis
2.6.3
2.创建 RedisUtil 类
package com.hyw.util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component;
import java.time.Duration;
import java.util.concurrent.TimeUnit;
@Component
public class RedisUtil {
@Autowired
private StringRedisTemplate redis;
public void setStr(String key, String value){
setStr(key, value, null);
}
public void setStr(String key, String value, Long timeOut){
redis.opsForValue().set(key, value);
if(timeOut != null)
redis.expire(key, timeOut, TimeUnit.SECONDS);
}
public Integer setnx(String key, String value, Long timeOut){
boolean flag = redis.opsForValue().setIfAbsent(key,value, timeOut, TimeUnit.SECONDS);
return flag?1:0;
}
public Integer setnx(String key, String value){
return setnx(key, value, null);
}
public void del(String key){
redis.delete(key);
}
public String getStr(String key){
return redis.opsForValue().get(key);
}
}
3.创建 RedisLock类
package com.hyw.lock;
import com.hyw.contans.OrderContans;
import com.hyw.util.RedisUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.util.UUID;
@Component
public class RedisLock {
@Autowired
private RedisUtil redisUtil;
public String getLock(String lockKey, int notLockTime){
//计算尝试获取锁超时时间
Long endTime = System.currentTimeMillis() + notLockTime;
//超时就退出循环
while (System.currentTimeMillis() < endTime){
String lockValue = UUID.randomUUID().toString();
if(redisUtil.setnx(lockKey, lockValue, notLockTime*1l/1000) == OrderContans.lockSuccess){
System.out.println(Thread.currentThread().getName() +"获取锁成功!");
return lockValue;
}
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
public void unlock(String lockKey, String lockValue){
//判断lockValue 是否抢到锁的用户,是就删除,避免把别人的锁给删了
if(lockValue.equals(redisUtil.getStr(lockKey))){
redisUtil.del(lockKey);
System.out.println(Thread.currentThread().getName() +"释放锁成功!");
}
}
}
4,创建常量类OrderContans
package com.hyw.contans;
public class OrderContans {
public static int lockSuccess = 1;
public static final String LOCK_KEY = "order_lock";
public static int notLockTime = 10000;
}
5,service成创建OrderService类,实现生成订单业务
package com.hyw.service;
import com.hyw.contans.OrderContans;
import com.hyw.lock.RedisLock;
import com.hyw.util.OrderUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
@Component
public class OrderService {
@Autowired
private RedisLock redisLock;
public void getOrderNum(){
//1.获取锁
String lockValue = redisLock.getLock(OrderContans.LOCK_KEY, OrderContans.notLockTime);
if(StringUtils.isEmpty(lockValue)){
System.out.println("获取锁失败!");
return;
}
System.out.println("获取订单号成功..."+ OrderUtil.getOrderNumber());
//3.释放锁
redisLock.unlock(OrderContans.LOCK_KEY, lockValue);
System.out.println();
}
}
6,创建控制器层OrderController,测试结果
package com.hyw.controller;
import com.hyw.service.OrderService;
import com.hyw.util.RedisUtil;
@RestController
public class OrderController {
@Autowired
private RedisUtil redisUtil;
@Autowired
private OrderService orderService;
@RequestMapping("/getOrderNum")
public String getOrderNum(){
for (int i = 0; i < 100; i++) {
new Thread(new Runnable() {
public void run() {
orderService.getOrderNum();
}
}).start();
}
return "success";
}
}
7,springboot启动类
package com.hyw;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import java.text.SimpleDateFormat;
import java.util.Date;
@SpringBootApplication
public class ApplicationMain {
public static void main(String[] args) {
SpringApplication.run(ApplicationMain.class, args);
}
}
运行结果:
http://localhost:8888/getOrderNum



