1.搭建集群

Linux系统的Redis各版本下载路径:https://download.redis.io/releases/,建议下载5.0以上的版本,下载后进行解压安装

(1)单机版

安装环境

yum install gcc-c++ -y

关闭防火墙

systemctl stop firewalld   #关闭
systemctl disable firewalld #永久关闭

解压

# 进入到redis安装目录,进行解压即可
cd /home/linux/redis
tar -xvf redis-5.0.13.tar.gz

修改配置文件

cd /home/linux/redis/redis-5.0.13/
vi redis.conf

修改的地方如下

bind 192.168.168.100  #绑定的ip,本机ip
#requirepass redis123 #密码,可以不加

进入redis-5.0.13进行编译

cd /home/linux/redis/redis-5.0.13/
make
cd src
make install



编译成功后会有对应的src、conf等文件夹

为了方便管理,将Redis文件中的conf配置文件和常用的命令移动到统一文件中创建bin和etc文件夹

cd /home/linux/redis/
mkdir bin etc

将redis.conf文件移动到home/linux/redis/etc目录下,将/src下的一些文件移到bin下

cd /home/linux/redis/redis-5.0.13/
mv redis.conf /home/linux/redis/etc
cd /home/linux/redis/redis-5.0.13/src
mv redis-trib.rb mkreleasehdr.sh redis-benchmark redis-check-aof redis-check-rdb redis-cli redis-server redis-sentinel /home/redis-6.0.6/bin

启动

bin/redis-server etc/redis.conf

客户端连接测试

(2)集群版

因为redis集群至少需要6台(3主3从),为了减少工作量我们选择在一台虚拟机上来完成搭建都任务。

建立文件夹

cd /home/linux/redis_cluster
mkdir 7001 7002 7003 7004 7005 7006

copy文件到目录下

cd redis-5.0.13/
cp etc/redis.conf /home/linux/redis_cluster/7001
cp etc/redis.conf /home/linux/redis_cluster/7002
cp etc/redis.conf /home/linux/redis_cluster/7003
cp etc/redis.conf /home/linux/redis_cluster/7004
cp etc/redis.conf /home/linux/redis_cluster/7005
cp etc/redis.conf /home/linux/redis_cluster/7006

修改配置文件

cd /home/linux/redis_cluster/7006
vi redis.conf

文件需要修改的内容如下

1)port 7001 //设置端口号

2)dir /usr/local/redis_cluster/7001/ //数据存放位置,必须要指定

3)cluster-enabled yes //启动集群模式

4)cluster-config-file nodes-7001.conf //集群节点信息文件

6)cluster-node-timeout 5000
7)appendonly yes //开启AOF模式,默认的持久化上RDB
8) appendfsync always //可以不加

其他7002....类似修改配置文件

测试启动

cd redis-5.0.13/bin
redis-server /home/soft/redis_cluster/7001/redis.conf

其他的也启动

启动完之后新开窗口加入集群

创建redis集群(5.0版本以后直接使用redis-cli)

redis-cli --cluster create  192.168.168.103:7001 192.168.168.103:7002 192.168.168.103:7003 192.168.168.103:7004 192.168.168.103:7005 192.168.168.103:7006 --cluster-replicas 1

//-a *** 密码 如果redis.conf中配置了密码创建集群时需要添加

2、springboot整合redis(单机、哨兵、集群)

依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent> <groupId>com.gblfy</groupId>
<artifactId>springboot2-redis</artifactId>
<version>0.0.1-SNAPSHOT</version> <name>springboot2-redis</name>
<description>Spring Boot整合redia 单机 哨兵 集群 三种方式</description> <properties>
<java.version>1.8</java.version>
</properties> <dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--redis Start-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis lettuce 依赖commons-pool -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--redis End--> <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--工具包-->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>
<dependency>
<groupId>commons-collections</groupId>
<artifactId>commons-collections</artifactId>
<version>3.2.2</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--序列化-->
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build> </project>

application.yml

server:
port: 80
spring:
profiles:
active:

(1)单机版模式

spring:
redis:
host: 192.168.0.114
port: 6379
### Redis数据库索引(默认为0)
database: 0
### 连接超时时间(毫秒)
timeout: 60000ms
password:
lettuce:
pool:
### 最大连接数(使用负值表示没有限制) 默认8
max-active: 8
### 最小空闲连接 默认8
min-idle: 0
### 连接池中的最大空闲连接 默认8
max-idle: 8
### 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms

(2)哨兵模式

#哨兵
spring:
redis:
sentinel:
master: mymaster
nodes:
- 192.168.0.114:26379
- 192.168.0.114:26380
- 192.168.0.114:26381
lettuce:
pool:
### 最大连接数(使用负值表示没有限制) 默认8
max-active: 8
### 最小空闲连接 默认8
min-idle: 0
### 连接池中的最大空闲连接 默认8
max-idle: 8
### 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
### 连接超时时间(毫秒)
timeout: 60000ms
password:

(3)集群模式

#集群
spring:
redis:
cluster:
nodes:
- 192.168.0.114:7001
- 192.168.0.114:7002
- 192.168.0.114:7003
- 192.168.0.114:7004
- 192.168.0.114:7005
- 192.168.0.114:7006
lettuce:
pool:
### 最大连接数(使用负值表示没有限制) 默认8
max-active: 8
### 最小空闲连接 默认8
min-idle: 0
### 连接池中的最大空闲连接 默认8
max-idle: 8
### 连接池最大阻塞等待时间(使用负值表示没有限制)
max-wait: -1ms
### 连接超时时间(毫秒)
timeout: 60000ms
password:

redis配置

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer; /**
* redis配置类
*
* @author gblfy
* @date 2020-04-19
*/
@Configuration
public class RedisConfig { @Bean
@SuppressWarnings("all")
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> redisTemplate = new RedisTemplate<String, Object>();
redisTemplate.setConnectionFactory(redisConnectionFactory); Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper); StringRedisSerializer stringRedisSerializer = new StringRedisSerializer(); // key采用String的序列化方式
redisTemplate.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
redisTemplate.setHashKeySerializer(stringRedisSerializer);
// valuevalue采用jackson序列化方式
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value采用jackson序列化方式
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
//开启事务支持
redisTemplate.setEnableTransactionSupport(true);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
}

redis工具类

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils; import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit; /**
* Redis工具类
*
* @author gblfy
* @date 2020-04-19
*/
@Component
public final class RedisUtils { @Autowired
private RedisTemplate<String, Object> redisTemplate; // =============================common============================ /**
* 指定缓存失效时间
*
* @param key 键
* @param time 时间(秒)
* @return
*/
public boolean expire(String key, long time) {
try {
if (time > 0) {
redisTemplate.expire(key, time, TimeUnit.SECONDS);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据key 获取过期时间
*
* @param key 键 不能为null
* @return 时间(秒) 返回0代表为永久有效
*/
public long getExpire(String key) {
return redisTemplate.getExpire(key, TimeUnit.SECONDS);
} /**
* 判断key是否存在
*
* @param key 键
* @return true 存在 false不存在
*/
public boolean hasKey(String key) {
try {
return redisTemplate.hasKey(key);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除缓存
*
* @param key 可以传一个值 或多个
*/
@SuppressWarnings("unchecked")
public void del(String... key) {
if (key != null && key.length > 0) {
if (key.length == 1) {
redisTemplate.delete(key[0]);
} else {
redisTemplate.delete(CollectionUtils.arrayToList(key));
}
}
} // ============================String============================= /**
* 普通缓存获取
*
* @param key 键
* @return 值
*/
public Object get(String key) {
return key == null ? null : redisTemplate.opsForValue().get(key);
} /**
* 普通缓存放入
*
* @param key 键
* @param value 值
* @return true成功 false失败
*/
public boolean set(String key, Object value) {
try {
redisTemplate.opsForValue().set(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 普通缓存放入并设置时间
*
* @param key 键
* @param value 值
* @param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期
* @return true成功 false 失败
*/
public boolean set(String key, Object value, long time) {
try {
if (time > 0) {
redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
} else {
set(key, value);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 递增
*
* @param key 键
* @param delta 要增加几(大于0)
* @return
*/
public long incr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递增因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, delta);
} /**
* 递减
*
* @param key 键
* @param delta 要减少几(小于0)
* @return
*/
public long decr(String key, long delta) {
if (delta < 0) {
throw new RuntimeException("递减因子必须大于0");
}
return redisTemplate.opsForValue().increment(key, -delta);
} // ================================Map================================= /**
* HashGet
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return 值
*/
public Object hget(String key, String item) {
return redisTemplate.opsForHash().get(key, item);
} /**
* 获取hashKey对应的所有键值
*
* @param key 键
* @return 对应的多个键值
*/
public Map<Object, Object> hmget(String key) {
return redisTemplate.opsForHash().entries(key);
} /**
* HashSet
*
* @param key 键
* @param map 对应多个键值
* @return true 成功 false 失败
*/
public boolean hmset(String key, Map<String, Object> map) {
try {
redisTemplate.opsForHash().putAll(key, map);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* HashSet 并设置时间
*
* @param key 键
* @param map 对应多个键值
* @param time 时间(秒)
* @return true成功 false失败
*/
public boolean hmset(String key, Map<String, Object> map, long time) {
try {
redisTemplate.opsForHash().putAll(key, map);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value) {
try {
redisTemplate.opsForHash().put(key, item, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 向一张hash表中放入数据,如果不存在将创建
*
* @param key 键
* @param item 项
* @param value 值
* @param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
* @return true 成功 false失败
*/
public boolean hset(String key, String item, Object value, long time) {
try {
redisTemplate.opsForHash().put(key, item, value);
if (time > 0) {
expire(key, time);
}
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 删除hash表中的值
*
* @param key 键 不能为null
* @param item 项 可以使多个 不能为null
*/
public void hdel(String key, Object... item) {
redisTemplate.opsForHash().delete(key, item);
} /**
* 判断hash表中是否有该项的值
*
* @param key 键 不能为null
* @param item 项 不能为null
* @return true 存在 false不存在
*/
public boolean hHasKey(String key, String item) {
return redisTemplate.opsForHash().hasKey(key, item);
} /**
* hash递增 如果不存在,就会创建一个 并把新增后的值返回
*
* @param key 键
* @param item 项
* @param by 要增加几(大于0)
* @return
*/
public double hincr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, by);
} /**
* hash递减
*
* @param key 键
* @param item 项
* @param by 要减少记(小于0)
* @return
*/
public double hdecr(String key, String item, double by) {
return redisTemplate.opsForHash().increment(key, item, -by);
} // ============================set============================= /**
* 根据key获取Set中的所有值
*
* @param key 键
* @return
*/
public Set<Object> sGet(String key) {
try {
return redisTemplate.opsForSet().members(key);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 根据value从一个set中查询,是否存在
*
* @param key 键
* @param value 值
* @return true 存在 false不存在
*/
public boolean sHasKey(String key, Object value) {
try {
return redisTemplate.opsForSet().isMember(key, value);
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将数据放入set缓存
*
* @param key 键
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSet(String key, Object... values) {
try {
return redisTemplate.opsForSet().add(key, values);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 将set数据放入缓存
*
* @param key 键
* @param time 时间(秒)
* @param values 值 可以是多个
* @return 成功个数
*/
public long sSetAndTime(String key, long time, Object... values) {
try {
Long count = redisTemplate.opsForSet().add(key, values);
if (time > 0)
expire(key, time);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 获取set缓存的长度
*
* @param key 键
* @return
*/
public long sGetSetSize(String key) {
try {
return redisTemplate.opsForSet().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 移除值为value的
*
* @param key 键
* @param values 值 可以是多个
* @return 移除的个数
*/
public long setRemove(String key, Object... values) {
try {
Long count = redisTemplate.opsForSet().remove(key, values);
return count;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} // ===============================list================================= /**
* 获取list缓存的内容
*
* @param key 键
* @param start 开始
* @param end 结束 0 到 -1代表所有值
* @return
*/
public List<Object> lGet(String key, long start, long end) {
try {
return redisTemplate.opsForList().range(key, start, end);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 获取list缓存的长度
*
* @param key 键
* @return
*/
public long lGetListSize(String key) {
try {
return redisTemplate.opsForList().size(key);
} catch (Exception e) {
e.printStackTrace();
return 0;
}
} /**
* 通过索引 获取list中的值
*
* @param key 键
* @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
* @return
*/
public Object lGetIndex(String key, long index) {
try {
return redisTemplate.opsForList().index(key, index);
} catch (Exception e) {
e.printStackTrace();
return null;
}
} /**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value) {
try {
redisTemplate.opsForList().rightPush(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, Object value, long time) {
try {
redisTemplate.opsForList().rightPush(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 将list放入缓存
*
* @param key 键
* @param value 值
* @param time 时间(秒)
* @return
*/
public boolean lSet(String key, List<Object> value, long time) {
try {
redisTemplate.opsForList().rightPushAll(key, value);
if (time > 0)
expire(key, time);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 根据索引修改list中的某条数据
*
* @param key 键
* @param index 索引
* @param value 值
* @return
*/
public boolean lUpdateIndex(String key, long index, Object value) {
try {
redisTemplate.opsForList().set(key, index, value);
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
} /**
* 移除N个值为value
*
* @param key 键
* @param count 移除多少个
* @param value 值
* @return 移除的个数
*/
public long lRemove(String key, long count, Object value) {
try {
Long remove = redisTemplate.opsForList().remove(key, count, value);
return remove;
} catch (Exception e) {
e.printStackTrace();
return 0;
}
}
}

源码参考:​https://gitee.com/gb_90/SpringBoot2_Practical_Column​

3、整合redisson

参考:https://blog.csdn.net/qq_27579471/article/details/103921489

redisson优势

提供了看门狗

Redisson提供了一个监控锁的看门狗(watch dog),它的作用是在Redisson实例被关闭前,不断(默认每10s)的延长锁(redis中的目标key)的有效期(默认续期到30s),也就是说,如果一个拿到锁的线程一直没有完成逻辑,那么看门狗会帮助线程不断的延长锁的超时时间,锁不会因为超时而被释放。加锁的业务只要运行完成,就不会给当前锁续期,即使不手动解锁,锁默认会在30s内自动过期,不会产生死锁问题;

默认情况下,看门狗的续期时间是30s,也可以通过修改Config.lockWatchdogTimeout来另行指定。

另外Redisson还提供了可以指定leaseTime参数的加锁方法来指定加锁的时间。超过这个时间后锁便自动解开了,不会延长锁的有效期。

提供了多种锁

redisson 还有公平锁、读写锁的实现。

public interface RedissonClient {
/**
* 获取锁(默认的非公平锁)
*/
RLock getLock(String name); /**
* 获取公平锁
*/
RLock getFairLock(String name); /**
* 获取读写锁
*/
RReadWriteLock getReadWriteLock(String name);
}
public interface RLock extends Lock, RExpirable, RLockAsync {
void lockInterruptibly(long leaseTime, TimeUnit unit) throws InterruptedException; boolean tryLock(long waitTime, long leaseTime, TimeUnit unit) throws InterruptedException; void lock(long leaseTime, TimeUnit unit); boolean forceUnlock(); boolean isLocked(); boolean isHeldByCurrentThread(); int getHoldCount();
}

添加依赖,注意redisson和springboot的版本对应

     <dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson-spring-boot-starter</artifactId>
<version>3.15.0</version> </dependency>

分析源码

redisson-spring-boot-starter这个包下只有2个类:RedissonProperties和RedissonAutoConfiguration。阅读源码发现RedissonAutoConfiguration会自动注册RedissonConnectionFactory和RedissonClient。



redisson-spring-boot-starter支持三种配置方式

方式一:完全兼容spring-boot-starter-data-redis的配置,即只需在application.yml中使用spring.redis来配置redis,redisson-spring-boot-starter会根据Redis的配置自动配置redisson。(已测试可行)

方式二:redisson的spring.redis.redisson.file方式,即在application.yml中使用spring.redis.redisson.file=classpath:redisson.yml来指定redisson的配置文件路径,然后在redisson.yml中配置redisson。

方式三:redisson的spring.redis.redisson.config方式,即在application.yml中使用spring.redis.redisson.config=xxx来直接配置Redisson。

多种方式的优先级:spring.redis.redisson.config > spring.redis.redisson.file> spring.redis。详细参考org.redisson.spring.starter.RedissonAutoConfiguration#redisson()。

简单使用

配置了redis和redisson的信息之后,就可以在项目中使用@Autowired注入org.redisson.api.RedissonClient(redisson提供的默认实现类是org.redisson.Redisson,且redisson-spring-boot-starter会自动往IOC容器中注册org.redisson.Redisson)。

Redis操作注入RedisTemplate进行使用。

Redission分布式锁可以引入RedissionClient进行使用。

@RestController
public class RedissonController { @Autowired
private RedissonClient redissonClient; @GetMapping(value = "/redisson/{key}")
public String redissonTest(@PathVariable("key") String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
try {
lock.lock();
Thread.sleep(10000);
} catch (Exception e) { } finally {
lock.unlock();
}
return "已解锁";
}
}

优化一下 封装redissonClient

package com.xx.core.redisson.lock;

/**
* Redisson分布式锁接口
* <p>
* RLock的实现有可重入非公平锁(RedissonLock)、可重入公平锁(RedissonFairLock)、联锁(RedissonMultiLock)、 红锁(RedissonRedLock)、 读锁(RedissonReadLock)、 写锁(RedissonWriteLock)等
*/
public interface DistributedLocker {
RLock lock(String lockKey); RLock lock(String lockKey, long timeout); RLock lock(String lockKey, TimeUnit unit, long timeout); boolean tryLock(String lockKey, TimeUnit unit, long leaseTime); boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime); void unlock(String lockKey); void unlock(RLock lock);
}
/**
* Redisson分布式锁实现-使用可重入非公平锁(RedissonLock)
*/
@Component
public class RedissonDistributedLocker implements DistributedLocker {
@Autowired
private RedissonClient redissonClient; public RLock lock(String lockKey) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock();
return lock;
} public RLock lock(String lockKey, long timeout) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock(timeout, TimeUnit.SECONDS);
return lock;
} public RLock lock(String lockKey, TimeUnit unit, long timeout) {
RLock lock = this.redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
} public boolean tryLock(String lockKey, TimeUnit unit, long leaseTime) {
RLock lock = this.redissonClient.getLock(lockKey);
try {
return lock.tryLock(0L, leaseTime, unit);
} catch (InterruptedException var7) {
return false;
}
} public boolean tryLock(String lockKey, TimeUnit unit, long waitTime, long leaseTime){
RLock lock = redissonClient.getLock(lockKey);
try {
return lock.tryLock(waitTime, leaseTime, unit);
} catch (InterruptedException e) {
return false;
}
} public void unlock(String lockKey){
RLock lock = redissonClient.getLock(lockKey);
try {
if (lock.isLocked()) {
lock.unlock();
}
} catch (IllegalMonitorStateException localIllegalMonitorStateException) {}
} public void unlock(RLock lock) {
try {
if (lock.isLocked()) {
lock.unlock();
}
} catch (IllegalMonitorStateException var3) {}
}
}

再优化一下,使用函数式DistributedLocker 接口新增tryLockAndRun()方法

public interface DistributedLocker {
/**
* @param lockKey
* @param unit
* @param waitTime
* @param leaseTime
* @param supplier 获取锁后要执行的业务逻辑
* @param scene 业务逻辑的场景,用于打印日志
* @param <T>
* @return
*/
<T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene);
}
public class RedissonDistributedLocker implements DistributedLocker {
@Override
public <T> T tryLockAndRun(@Nonnull String lockKey, @Nonnull TimeUnit unit, long waitTime, long leaseTime, @Nonnull Supplier<T> supplier, String scene) {
final long start = SystemClock.now();
// 获取分布式锁,最长等待时间:10秒,20秒后自动释放。注意锁与事务的顺序:获取分布式锁 -> 开启事务 -> 执行业务 -> 提交事务 -> 释放分布式锁!!!
final boolean tryLock = this.tryLock(lockKey, unit, waitTime, leaseTime);
final long end = SystemClock.now();
if (!tryLock) {
log.error("[{}]获取分布式锁失败,lockKey = {},耗时{}ms", scene, lockKey, end - start);
throw new RequestResultException(JsonCommonCodeEnum.E0004);
} // 注意:一定是获取锁成功后,才进行try{}finally{释放锁}
try {
log.info("[{}]获取分布式锁成功,lockKey = {},耗时{}ms", scene, lockKey, end - start);
return supplier.get();
} finally {
this.unlock(lockKey);
}
}
}

4、问题处理

redis单机、主从、哨兵、集群以及redisson分布式锁的更多相关文章

  1. Redis主从&哨兵集群搭建

    主从集群 在搭建主从集群前,我们先把Redis安装起来: #解压Redis压缩包 [root@master lf]# tar -zxvf redis-6.2.1.tar.gz -- #安装gcc [r ...

  2. C#两大知名Redis客户端连接哨兵集群的姿势

    前言 前面利用<Docker-Compose搭建Redis高可用哨兵集群>, 我们的思路是将Redis.Sentinel.Redis Client App链接到同一个网桥网络,这个网桥内的 ...

  3. 阿里云ECS部署Redis主备哨兵集群遇到的问题

    一.部署 详细部署步骤:https://blog.csdn.net/lihongtai/article/details/82826809 Redis5.0版本需要注意的参数配置:https://www ...

  4. 三千字介绍Redis主从+哨兵+集群

    一.Redis持久化策略 1.RDB 每隔几分钟或者一段时间会将redis内存中的数据全量的写入到一个文件中去. 优点: 因为他是每隔一段时间的全量备份,代表了每个时间段的数据.所以适合做冷备份. R ...

  5. 【Redis学习专题】- Redis主从+哨兵集群部署

    集群版本: redis-4.0.14 集群节点: 节点角色 IP redis-master 10.100.8.21 redis-slave1 10.100.8.22 redis-slave2 10.1 ...

  6. 项目实战11—企业级nosql数据库应用与实战-redis的主从和集群

    企业级nosql数据库应用与实战-redis 环境背景:随着互联网2.0时代的发展,越来越多的公司更加注重用户体验和互动,这些公司的平台上会出现越来越多方便用户操作和选择的新功能,如优惠券发放.抢红包 ...

  7. Redis集合 安装 哨兵集群 配置

    redis相关 redis基础 redis发布订阅 redis持久化RDB与AOF redis不重启,切换RDB备份到AOF备份 redis安全配置 redis主从同步 redis哨兵集群 redis ...

  8. redis系列--深入哨兵集群

    一.前言 在之前的系列文章中介绍了redis的入门.持久化以及复制功能,如果不了解请移步至redis系列进行阅读,当然我也是抱着学习的知识分享,如果有什么问题欢迎指正,也欢迎大家转载.而本次将介绍哨兵 ...

  9. Redis单机安装以及集群搭建

    今天主要来看一下Redis的安装以及集群搭建(我也是第一次搭建). 环境:CentOS 7.1,redis-5.0.7 一.单机安装 1.将Redis安装包放置服务器并解压 2.进入redis安装目录 ...

  10. redis 单机模拟 cluster集群

    一.redis-cluster设计 Redis集群搭建的方式有多种,例如使用zookeeper等,但从redis 3.0之后版本支持redis-cluster集群,Redis-Cluster采用无中心 ...

随机推荐

  1. ODOO13之 八:Odoo 13开发之业务逻辑 – 业务流程的支持

    在前面的文章中,我们学习了模型层.如何创建应用数据结构以及如何使用 ORM API 来存储查看数据.本文中我们将利用前面所学的模型和记录集知识实现应用中常用的业务逻辑模式. 本文的主要内容有: 以单据 ...

  2. 国标GB28181协议客户端开发(一)整体流程和技术选型

    国标GB28181协议客户端开发(一)整体流程和技术选型 本系列文章将介绍国标GB28181协议设备端的开发过程.本文旨在探讨整体设计和技术选型方面的考虑,为开发人员提供指导和参考.文章将从设备端开发 ...

  3. 使用CosmosDB进行大规模数据的实时数据处理和流式传输

    目录 使用 Cosmos DB 进行大规模数据的实时数据处理和流式传输 背景介绍 文章目的 目标受众 技术原理及概念 基本概念解释 技术原理介绍 相关技术比较 实现步骤与流程 准备工作:环境配置与依赖 ...

  4. 生成式预训练Transformer在机器翻译中的应用与挑战

    目录 1. 引言 2. 技术原理及概念 3. 实现步骤与流程 4. 应用示例与代码实现讲解 5. 优化与改进 6. 结论与展望 机器翻译是人工智能领域的重要应用之一,而生成式预训练Transforme ...

  5. DevChat:将 GPT-4 无缝融入 VS Code,极致提升你的编程体验

    目录 一.絮絮叨叨 1.1 缘起 1.2 嫌弃 1.3 征服 二.认真聊聊 2.1 老板给了少年一个任务 2.2 少年祭出了 DevChat 2.3 让 DevChat 帮着选 web 框架 2.4 ...

  6. SQL SERVER 拼接字符串转化为表结构数据

    本文为一些需要对特殊符号分隔的字符串进行解析,比如将 select '10,20,30,40,50,60' 这个字符串转化为一列多行 下面提供源代码: 1 SET QUOTED_IDENTIFIER ...

  7. P8903 [USACO22DEC] Bribing Friends G 看电影

    P8903 [USACO22DEC] Bribing Friends G 看电影 目录 P8903 [USACO22DEC] Bribing Friends G 看电影 题目描述 输入格式 输出格式 ...

  8. 🎉Avalonia 11.0.0 正式版发布

    Avalonia 11.0.0 正式版发布! AvaloniaUI 发布11.0.0正式版 终于avalonia发布了正式版. 更新内容 A11y(辅助功能) 这个版本的Avalonia在使应用程序更 ...

  9. 「学习笔记」KMP 算法

    前置知识 前缀 是指从串首开始到某个位置 \(i\) 结束的一个特殊子串. 真前缀 指除了 \(S\) 本身的 \(S\) 的前缀. 举例来说, 字符串 abcabeda 的所有前缀为 {a, ab, ...

  10. Day01_Java作业

    A:选择题 1:下列标识符哪个是合法的(a) A.class B.$abc C.1234 D.Car.taxi B:填空题 1: java源程序的扩展名是( .java ) 2: java程序经编译后 ...