1.引用jar
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.11.3</version>
</dependency>
2.redisson 配置
/**
-
redisson配置
-
公共配置
-
- 多主节点的环境里,每个 主节点的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
-
- idleConnectionTimeout(连接空闲超时,单位:毫秒)
-
- 默认值:10000
-
-
- 如果当前连接池里的连接数量超过了最小空闲连接数,而同时有连接空闲时间超过了该数值,那么这些连接将会自动被关闭,并从连接池里去掉。时间单位是毫秒。
-
-
- connectTimeout(连接超时,单位:毫秒)
-
- 默认值:10000
-
-
- 同任何节点建立连接时的等待超时。时间单位是毫秒。
-
-
- timeout(命令等待超时,单位:毫秒)
-
- 默认值:3000
-
-
- 等待节点回复命令的时间。该时间从命令发送成功时开始计时。
-
-
- retryAttempts(命令失败重试次数)
-
- 默认值:3
-
-
- 如果尝试达到 retryAttempts(命令失败重试次数) 仍然不能将命令发送至某个指定的节点时,将抛出错误。如果尝试在此限制之内发送成功,则开始启用 timeout(命令等待超时) 计时。
-
-
- retryInterval(命令重试发送时间间隔,单位:毫秒)
-
- 默认值:1500
-
-
- 在一条命令发送失败以后,等待重试发送的时间间隔。时间单位是毫秒。
-
-
- reconnectionTimeout(重新连接时间间隔,单位:毫秒)
-
- 默认值:3000
-
-
- 当与某个节点的连接断开时,等待与其重新建立连接的时间间隔。时间单位是毫秒。
-
-
- failedAttempts(执行失败最大次数)
-
- 默认值:3
-
-
- 在某个节点执行相同或不同命令时,连续 失败 failedAttempts(执行失败最大次数) 时,该节点将被从可用节点列表里清除,直到 reconnectionTimeout(重新连接时间间隔) 超时以后再次尝试。
-
-
- password(密码)
-
- 默认值:null
-
-
- 用于节点身份验证的密码。
-
-
- subscriptionsPerConnection(单个连接最大订阅数量)
-
- 默认值:5
-
-
- 每个连接的最大订阅数量。
-
-
- clientName(客户端名称)
-
- 默认值:null
-
-
- 在Redis节点里显示的客户端名称。
-
-
- sslEnableEndpointIdentification(启用SSL终端识别)
-
- 默认值:true
-
-
- 开启SSL终端识别能力。
-
-
- sslProvider(SSL实现方式)
-
- 默认值:JDK
-
-
- 确定采用哪种方式(JDK或OPENSSL)来实现SSL连接。
-
-
- sslTruststore(SSL信任证书库路径)
-
- 默认值:null
-
-
- 指定SSL信任证书库的路径。
-
-
- sslTruststorePassword(SSL信任证书库密码)
-
- 默认值:null
-
-
- 指定SSL信任证书库的密码。
-
-
- sslKeystore(SSL钥匙库路径)
-
- 默认值:null
-
-
- 指定SSL钥匙库的路径。
-
-
- sslKeystorePassword(SSL钥匙库密码)
-
- 默认值:null
-
-
- 指定SSL钥匙库的密码。
-
集群设置
-
config.useClusterServers();
//可以用"rediss://"来启用SSL连接
.addNodeAddress(“redis://127.0.0.1:7000”, “redis://127.0.0.1:7001”)
.addNodeAddress(“redis://127.0.0.1:7002”); -
nodeAddresses(添加节点地址)
-
可以通过host:port的格式来添加Redis集群节点的地址。多个节点可以一次性批量添加。
-
scanInterval(集群扫描间隔时间)
-
默认值: 1000
-
对Redis集群节点状态扫描的时间间隔。单位是毫秒。
-
slots(分片数量)
-
默认值: 231 用于指定数据分片过程中的分片数量。支持数据分片/框架结构有:集(Set)、映射(Map)、BitSet、Bloom filter, Spring Cache和Hibernate Cache等.
-
readMode(读取操作的负载均衡模式)
-
默认值: SLAVE(只在从服务节点里读取)
-
注:在从服务节点里读取的数据说明已经至少有两个节点保存了该数据,确保了数据的高可用性。
-
设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。 MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取。
-
subscriptionMode(订阅操作的负载均衡模式)
-
默认值:SLAVE(只在从服务节点里订阅)
-
设置订阅操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里订阅。 MASTER - 只在主服务节点里订阅。
-
loadBalancer(负载均衡算法类的选择)
-
默认值: org.redisson.connection.balancer.RoundRobinLoadBalancer
-
在多Redis服务节点的环境里,可以选用以下几种负载均衡方式选择一个节点: org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法 org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法 org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
-
subscriptionConnectionMinimumIdleSize(从节点发布和订阅连接的最小空闲连接数)
-
默认值:1
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的最小保持连接数(长连接)。Redisson内部经常通过发布和订阅来实现许多功能。长期保持一定数量的发布订阅连接是必须的。
-
subscriptionConnectionPoolSize(从节点发布和订阅连接池大小)
-
默认值:50
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
slaveConnectionMinimumIdleSize(从节点最小空闲连接数)
-
默认值:32
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时读取反映速度。
-
slaveConnectionPoolSize(从节点连接池大小)
-
默认值:64
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
masterConnectionMinimumIdleSize(主节点最小空闲连接数)
-
默认值:32
-
多节点的环境里,每个 主节点的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。
-
masterConnectionPoolSize(主节点连接池大小)
-
默认值:64
-
单Redis节点模式
-
2.6.1. 单节点设置
-
Redis程序的配置和架设文档在这里。Redisson的单Redis节点模式的使用方法如下: SingleServerConfig singleConfig = config.useSingleServer();
-
SingleServerConfig 类的设置参数如下:
-
address(节点地址)
-
可以通过host:port的格式来指定节点地址。
-
subscriptionConnectionMinimumIdleSize(发布和订阅连接的最小空闲连接数)
-
默认值:1
-
用于发布和订阅连接的最小保持连接数(长连接)。Redisson内部经常通过发布和订阅来实现许多功能。长期保持一定数量的发布订阅连接是必须的。
-
subscriptionConnectionPoolSize(发布和订阅连接池大小)
-
默认值:50
-
用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
connectionMinimumIdleSize(最小空闲连接数)
-
默认值:32
-
最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。
-
connectionPoolSize(连接池大小)
-
默认值:64
-
连接池最大容量。连接池的连接数量自动弹性伸缩。
-
dnsMonitoring(是否启用DNS监测)
-
默认值:false
-
在启用该功能以后,Redisson将会监测DNS的变化情况。
-
dnsMonitoringInterval(DNS监测时间间隔,单位:毫秒)
-
默认值:5000
-
监测DNS的变化情况的时间间隔。
-
哨兵模式
-
config.useSentinelServers();
-
可以用"rediss://"来启用SSL连接
-
.addSentinelAddress(“127.0.0.1:26389”, “127.0.0.1:26379”)
-
.addSentinelAddress(“127.0.0.1:26319”);
-
dnsMonitoringInterval(DNS监控间隔,单位:毫秒)
-
默认值:5000
-
用来指定检查节点DNS变化的时间间隔。使用的时候应该确保JVM里的DNS数据的缓存时间保持在足够低的范围才有意义。用-1来禁用该功能。
-
masterName(主服务器的名称)
-
主服务器的名称是哨兵进程中用来监测主从服务切换情况的。
-
addSentinelAddress(添加哨兵节点地址)
-
可以通过host:port的格式来指定哨兵节点的地址。多个节点可以一次性批量添加。
-
readMode(读取操作的负载均衡模式)
-
默认值: SLAVE(只在从服务节点里读取)
-
注:在从服务节点里读取的数据说明已经至少有两个节点保存了该数据,确保了数据的高可用性。
-
设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。 MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取。
-
subscriptionMode(订阅操作的负载均衡模式)
-
默认值:SLAVE(只在从服务节点里订阅)
-
设置订阅操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里订阅。 MASTER - 只在主服务节点里订阅。
-
loadBalancer(负载均衡算法类的选择)
-
默认值: org.redisson.connection.balancer.RoundRobinLoadBalancer
-
在使用多个Redis服务节点的环境里,可以选用以下几种负载均衡方式选择一个节点: org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法 org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法 org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
-
subscriptionConnectionMinimumIdleSize(从节点发布和订阅连接的最小空闲连接数)
-
默认值:1
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的最小保持连接数(长连接)。Redisson内部经常通过发布和订阅来实现许多功能。长期保持一定数量的发布订阅连接是必须的。
-
subscriptionConnectionPoolSize(从节点发布和订阅连接池大小)
-
默认值:50
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
slaveConnectionMinimumIdleSize(从节点最小空闲连接数)
-
默认值:32
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时读取反映速度。
-
slaveConnectionPoolSize(从节点连接池大小)
-
默认值:64
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
masterConnectionMinimumIdleSize(主节点最小空闲连接数)
-
默认值:32
-
多从节点的环境里,每个 主节点的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。
-
masterConnectionPoolSize(主节点连接池大小)
-
默认值:64
-
主节点的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
主从模式
-
config.useMasterSlaveServers();
*.setMasterAddress(“redis://127.0.0.1:6379”) -
.addSlaveAddress(“redis://127.0.0.1:6389”, “redis://127.0.0.1:6332”, “redis://127.0.0.1:6419”)
-
.addSlaveAddress(“redis://127.0.0.1:6399”);
-
dnsMonitoringInterval(DNS监控间隔,单位:毫秒)
-
默认值:5000
-
用来指定检查节点DNS变化的时间间隔。使用的时候应该确保JVM里的DNS数据的缓存时间保持在足够低的范围才有意义。用-1来禁用该功能。
-
masterAddress(主节点地址)
-
可以通过host:port的格式来指定主节点地址。
-
addSlaveAddress(添加从主节点地址)
-
可以通过host:port的格式来指定从节点的地址。多个节点可以一次性批量添加。
-
readMode(读取操作的负载均衡模式)
-
默认值: SLAVE(只在从服务节点里读取)
-
注:在从服务节点里读取的数据说明已经至少有两个节点保存了该数据,确保了数据的高可用性。
-
设置读取操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里读取。 MASTER - 只在主服务节点里读取。 MASTER_SLAVE - 在主从服务节点里都可以读取。
-
subscriptionMode(订阅操作的负载均衡模式)
-
默认值:SLAVE(只在从服务节点里订阅)
-
设置订阅操作选择节点的模式。 可用值为: SLAVE - 只在从服务节点里订阅。 MASTER - 只在主服务节点里订阅。
-
loadBalancer(负载均衡算法类的选择)
-
默认值: org.redisson.connection.balancer.RoundRobinLoadBalancer
-
在使用多个Redis服务节点的环境里,可以选用以下几种负载均衡方式选择一个节点: org.redisson.connection.balancer.WeightedRoundRobinBalancer - 权重轮询调度算法 org.redisson.connection.balancer.RoundRobinLoadBalancer - 轮询调度算法 org.redisson.connection.balancer.RandomLoadBalancer - 随机调度算法
-
subscriptionConnectionMinimumIdleSize(从节点发布和订阅连接的最小空闲连接数)
-
默认值:1
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的最小保持连接数(长连接)。Redisson内部经常通过发布和订阅来实现许多功能。长期保持一定数量的发布订阅连接是必须的。
-
subscriptionConnectionPoolSize(从节点发布和订阅连接池大小)
-
默认值:50
-
多从节点的环境里,每个 从服务节点里用于发布和订阅连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
slaveConnectionMinimumIdleSize(从节点最小空闲连接数)
-
默认值:32
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时读取反映速度。
-
slaveConnectionPoolSize(从节点连接池大小)
-
默认值:64
-
多从节点的环境里,每个 从服务节点里用于普通操作(非 发布和订阅)连接的连接池最大容量。连接池的连接数量自动弹性伸缩。
-
masterConnectionMinimumIdleSize(主节点最小空闲连接数)
-
默认值:32
-
多从节点的环境里,每个 主节点的最小保持连接数(长连接)。长期保持一定数量的连接有利于提高瞬时写入反应速度。
-
masterConnectionPoolSize(主节点连接池大小)
-
默认值:64
-
主节点的连接池最大容量。连接池的连接数量自动弹性伸缩。
*/
@Configuration
public class RedissonManager{
@Bean
public RedissonClient getRedisson(){
//redisson版本是3.5,集群的ip前面要加上“redis://”,不然会报错,3.2版本可不加
RedissonClient redisson = null;
Config config = new Config();
config.useSingleServer()
.setAddress("redis://127.0.0.1:6379");
redisson = Redisson.create(config);
return redisson;
}
}
3.定义工具类方便调用方使用
@Component
public class RedissonLockUtil {
private static DistributedLocker redissLock;
@Autowired
private DistributedLocker redisClient;
@PostConstruct
public void init() {
this.redissLock = redisClient;
}
/**
* 加锁
* @param lockKey
* @return
*/
public static RLock lock(String lockKey) {
return redissLock.lock(lockKey);
}
/**
* 释放锁
* @param lockKey
*/
public static void unlock(String lockKey) {
redissLock.unlock(lockKey);
}
/**
* 释放锁
* @param lock
*/
public static void unlock(RLock lock) {
redissLock.unlock(lock);
}
/**
* 带超时的锁
* @param lockKey
* @param timeout 超时时间 单位:秒
*/
public static RLock lock(String lockKey, int timeout) {
return redissLock.lock(lockKey, timeout);
}
/**
* 带超时的锁
* @param lockKey
* @param unit 时间单位
* @param timeout 超时时间
*/
public static RLock lock(String lockKey, TimeUnit unit , int timeout) {
return redissLock.lock(lockKey, unit, timeout);
}
/**
* 尝试获取锁
* @param lockKey
* @param waitTime 最多等待时间
* @param leaseTime 上锁后自动释放锁时间
* @return
*/
public static boolean tryLock(String lockKey, int waitTime, int leaseTime) {
return redissLock.tryLock(lockKey, TimeUnit.SECONDS, waitTime, leaseTime);
}
/**
* 尝试获取锁
* @param lockKey
* @param unit 时间单位
* @param waitTime 最多等待时间
* @param leaseTime 上锁后自动释放锁时间
* @return
*/
public static boolean tryLock(String lockKey, TimeUnit unit, int waitTime, int leaseTime) {
return redissLock.tryLock(lockKey, unit, waitTime, leaseTime);
}
public static String getString(String key){
return redissLock.getString(key);
}
public static void setString(String key, Object value){
redissLock.setString(key,value);
}
}
5.定一个接口和实现类
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 waitTime, long leaseTime);
void unlock(String lockKey);
void unlock(RLock lock);
String getString(String key);
void setString(String key, Object value);
boolean hasString(String key);
long incr(String key, long delta);
}
@Service
public class RedissonDistributedLocker implements DistributedLocker {
//RedissonClient已经由配置类生成,这里自动装配即可
@Autowired
private RedissonClient redissonClient;
//lock(), 拿不到lock就不罢休,不然线程就一直block
@Override
public RLock lock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock();
return lock;
}
//leaseTime为加锁时间,单位为秒
@Override
public RLock lock(String lockKey, long leaseTime) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(leaseTime, TimeUnit.SECONDS);
return lock;
}
//timeout为加锁时间,时间单位由unit确定
@Override
public RLock lock(String lockKey, TimeUnit unit ,long timeout) {
RLock lock = redissonClient.getLock(lockKey);
lock.lock(timeout, unit);
return lock;
}
//tryLock(),马上返回,拿到lock就返回true,不然返回false。
//带时间限制的tryLock(),拿不到lock,就等一段时间,超时返回false.
@Override
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;
}
}
@Override
public void unlock(String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
lock.unlock();
}
@Override
public void unlock(RLock lock) {
lock.unlock();
}
@Override
public String getString(String key) {
RBucket<Object> bucket = redissonClient.getBucket(key);
return bucket.get() == null ? null : bucket.get().toString();
}
@Override
public void setString(String key, Object value) {
RBucket<Object> result = this.redissonClient.getBucket(key);
if (!result.isExists()) {
result.set(value, 5, TimeUnit.MINUTES);
}
}
@Override
public boolean hasString(String key) {
RBucket<Object> result = redissonClient.getBucket(key);
if (result.isExists()) {
return true;
} else {
return false;
}
}
@Override
public long incr(String key, long delta) {
return redissonClient.getAtomicLong(key).addAndGet(delta);
}
}
6.controller
@RestController
@RequestMapping("/redisson")
public class AdvMaterialController {
// @Autowired
// private DistributedLocker distributedLocker;
@RequestMapping("/test")
public void redissonTest() {
String key = “redisson_key”;
for (int i = 0; i < 100; i++) {
Thread t = new Thread(new Runnable() {
@Override
public void run() {
try {
System.err.println("=线程开启"+Thread.currentThread().getName());
/*distributedLocker.lock(key,10L); //直接加锁,获取不到锁则一直等待获取锁
Thread.sleep(100); //获得锁之后可以进行相应的处理
System.err.println(“获得锁后进行相应的操作”+Thread.currentThread().getName());
distributedLocker.unlock(key); //解锁
System.err.println("============================="+Thread.currentThread().getName());*/
boolean isGetLock = RedissonLockUtil.tryLock(key, TimeUnit.SECONDS,5,10); //尝试获取锁,等待5秒,自己获得锁后一直不解锁则10秒后自动解锁
if(isGetLock){
Thread.sleep(100); //获得锁之后可以进行相应的处理
System.err.println("======获得锁后进行相应的操作======"+Thread.currentThread().getName());
//distributedLocker.unlock(key);
System.err.println("============================="+Thread.currentThread().getName());
}
} catch (Exception e) {
e.printStackTrace();
}finally {
RedissonLockUtil.unlock(key);
}
}
});
t.start();
}
}
@RequestMapping("/test1")
public void redissonSetTest() {
RedissonLockUtil.setString("test","abc");
}
@RequestMapping("/test2")
public String redissonGetTest() {
return RedissonLockUtil.getString("test");
}