rediSsion 分布式锁使用
1场景设定
假定两个不同服务去请求消耗剩余商品库存数(100)
商品库存为100,数目模拟存在redis中。key值number,value100
2存值
存入方式选StringRedisTemplate存储或者jedis存储。
1 StringRedisTemplate存储
引入相关pom文件
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
配置yml
spring:
application:
name: User
redis:
database: 7
host: *******
jedis:
pool:
max-active: 100
max-idle: 20
max-wait: -1ms
password: *******
port: 6379
timeout: 20
redisjedis:
pool:
min-idle: 0
@Autowired注入使用
@Autowired
private StringRedisTemplate stringRedisTemplate;//自带的字符串模板类,用于存储字符串
stringRedisTemplate.opsForValue().set("number","100");
2 jedis存储(使用jedispool)
引入相关pom文件
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>${jedis.version}</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>${redisson.version}</version>
</dependency>
配置yml(同上)
添加配置类
/**
* zbeing
*/
@Configuration
public class RedisUtil {
private static Integer maxToal;
private static String host;
private static Integer prot;
private static Integer timeout;
private static String password;
@Value("${spring.redis.jedis.pool.max-active}")
public void setMaxToal(Integer maxToal) {
RedisUtil.maxToal = maxToal;
}
@Value("${spring.redis.host}")
public void setHost(String host) {
RedisUtil.host = host;
}
@Value("${spring.redis.port}")
public void setProt(Integer prot) {
RedisUtil.prot = prot;
}
@Value("${spring.redis.timeout}")
public void setTimeout(Integer timeout) {
RedisUtil.timeout = timeout;
}
@Value("${spring.redis.password}")
public void setPassword(String password) {
RedisUtil.password = password;
}
public static void saveRedis(String key, String value) {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
jedisPoolConfig.setMaxTotal(maxToal);
JedisPool pool = new JedisPool(jedisPoolConfig, host, prot,timeout,password,7);
Jedis jedis = null;
try {
jedis = pool.getResource();
jedis.set(key, value);
System.out.println("已存入的redis值" + jedis.get(key));
} catch (Exception e) {
e.printStackTrace();
} finally {
//还回pool中
if (jedis != null) {
jedis.close();
}
}
pool.close();
}
}
注:因为JedisPoolpool的util是工具类(静态),所以交由spring管理时,静态属性赋值要采用上述set属性时进行赋值
使用
RedisUtil.saveRedis("number","100");
3 redisson
1redisson 配置类
/**
* zbeing
*/
@Configuration
public class RedissonConfig {
@Value("${spring.redis.database}")
private int database;
@Value("${spring.redis.host}")
private String host;
@Value("${spring.redis.port}")
private String port;
@Value("${spring.redis.password}")
private String password;
@Value("${spring.redis.timeout}")
private int timeout;
/**
* RedissonClient,单机模式
*
* @return
* @throws IOException
*/
@Bean(destroyMethod = "shutdown")
public RedissonClient redisson() {
Config config = new Config();
SingleServerConfig singleServerConfig = config.useSingleServer();
singleServerConfig.setAddress("redis://" + host + ":" + port);
singleServerConfig.setTimeout(timeout);
singleServerConfig.setDatabase(database);
System.out.println("获取"+JSON.toJSONString(singleServerConfig));
if (password != null && !"".equals(password)) { //有密码
singleServerConfig.setPassword(password);
}
return Redisson.create(config);
}
}
2redisson使用
static final String KEY = "LOCK_KEY";
@Autowired
private RedissonClient redissonClient;
@GetMapping("/test")
public Object test(){
for (int i = 0; i <100 ; i++) {
new Thread(()->{
redissonClient.getLock(KEY).lock();
//LockUtil.lock(KEY);
try {
String number = stringRedisTemplate.opsForValue().get("number");
int num = Integer.parseInt(number);
System.out.println("获取的数目"+num);
Thread.sleep(1000);
if(num>0&&num<=100){
System.out.println(" 处理业务。。。");
stringRedisTemplate.opsForValue().set("number",String.valueOf(num- 1));
}
} catch (Exception e) {
//异常处理
}finally{
//释放锁
// LockUtil.unlock(KEY);
redissonClient.getLock(KEY).unlock();
}
}
).start();
}
//加锁
return "SUCCESS";
}
3演示
存入redis值
进行不同服务调用
得到结果
4 redisson优化
package com.demo.p.util;
import java.util.concurrent.TimeUnit;
public interface Locker {
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。
*
* @param lockKey
*/
void lock(String lockKey);
/**
* 释放锁
*
* @param lockKey
*/
void unlock(String lockKey);
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。如果获取到锁后,执行结束后解锁或达到超时时间后会自动释放锁
*
* @param lockKey
* @param timeout
*/
void lock(String lockKey, int timeout);
/**
* 获取锁,如果锁不可用,则当前线程处于休眠状态,直到获得锁为止。如果获取到锁后,执行结束后解锁或达到超时时间后会自动释放锁
*
* @param lockKey
* @param unit
* @param timeout
*/
void lock(String lockKey, TimeUnit unit, int timeout);
/**
* 尝试获取锁,获取到立即返回true,未获取到立即返回false
*
* @param lockKey
* @return
*/
boolean tryLock(String lockKey);
/**
* 尝试获取锁,在等待时间内获取到锁则返回true,否则返回false,如果获取到锁,则要么执行完后程序释放锁,
* 要么在给定的超时时间leaseTime后释放锁
*
* @param lockKey
* @param waitTime
* @param leaseTime
* @param unit
* @return
*/
boolean tryLock(String lockKey, long waitTime, long leaseTime, TimeUnit unit)
throws InterruptedException;
/**
* 锁是否被任意一个线程锁持有
*
* @param lockKey
* @return
*/
boolean isLocked(String lockKey);
}
package com.demo.p.util;
import java.util.concurrent.TimeUnit;
public class LockUtil {
private static Locker locker;
/**
* 设置工具类使用的locker
*
* @param locker
*/
public static void setLocker(Locker locker) {
LockUtil.locker = locker;
}
/**
* 获取锁
*
* @param lockKey
*/
public static void lock(String lockKey) {
locker.lock(lockKey);
}
/**
* 释放锁
*
* @param lockKey
*/
public static void unlock(String lockKey) {
locker.unlock(lockKey);
}
/**
* 获取锁,超时释放
*
* @param lockKey
* @param timeout
*/
public static void lock(String lockKey, int timeout) {
locker.lock(lockKey, timeout);
}
/**
* 获取锁,超时释放,指定时间单位
*
* @param lockKey
* @param unit
* @param timeout
*/
public static void lock(String lockKey, TimeUnit unit, int timeout) {
locker.lock(lockKey, unit, timeout);
}
/**
* 尝试获取锁,获取到立即返回true,获取失败立即返回false
*
* @param lockKey
* @return
*/
public static boolean tryLock(String lockKey) {
return locker.tryLock(lockKey);
}
/**
* 尝试获取锁,在给定的waitTime时间内尝试,获取到返回true,获取失败返回false,获取到后再给定的leaseTime时间超时释放
*
* @param lockKey
* @param waitTime
* @param leaseTime
* @param unit
* @return
* @throws InterruptedException
*/
public static boolean tryLock(String lockKey, long waitTime, long leaseTime,
TimeUnit unit) throws InterruptedException {
return locker.tryLock(lockKey, waitTime, leaseTime, unit);
}
/**
* 锁释放被任意一个线程持有
*
* @param lockKey
* @return
*/
public static boolean isLocked(String lockKey) {
return locker.isLocked(lockKey);
}
}
@GetMapping("/test")
public Object test(){
for (int i = 0; i <100 ; i++) {
new Thread(()->{
//redissonClient.getLock(KEY).lock();
LockUtil.lock(KEY);
try {
String number = stringRedisTemplate.opsForValue().get("number");
int num = Integer.parseInt(number);
System.out.println("获取的数目"+num);
Thread.sleep(1000);
if(num>0&&num<=100){
System.out.println(" 处理业务。。。");
stringRedisTemplate.opsForValue().set("number",String.valueOf(num- 1));
}
} catch (Exception e) {
//异常处理
}finally{
//释放锁
LockUtil.unlock(KEY);
// redissonClient.getLock(KEY).unlock();
}
}
).start();
}
//加锁
return "SUCCESS";
}