springBoot2.*使用redis集群/單機方法
- 2022 年 2 月 12 日
- 筆記
在springboot1.x系列中,其中使用的是jedis,但是到了springboot2.x其中使用的是Lettuce。 此處springboot2.x,所以使用的是Lettuce。
關於jedis跟lettuce的區別:
- Lettuce 和 Jedis 的定位都是Redis的client,所以他們當然可以直接連接redis server。
- Jedis在實現上是直接連接的redis server,如果在多執行緒環境下是非執行緒安全的,這個時候只有使用連接池,為每個Jedis實例增加物理連接
- Lettuce的連接是基於Netty的,連接實例(StatefulRedisConnection)可以在多個執行緒間並發訪問,應為StatefulRedisConnection是執行緒安全的,所以一個連接實例(StatefulRedisConnection)就可以滿足多執行緒環境下的並發訪問,當然這個也是可伸縮的設計,一個連接實例不夠的情況也可以按需增加連接實例。
新建一個springboot工程,添加如下pom依賴。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- redis依賴commons-pool 這個依賴一定要添加 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
application.yml配置一下redis伺服器的地址(其中nodes為集群redis的參數 host為單機redis的參數)
#REDIS
redis:
cache:
nodes: #-192.168.1.2:7001 前面使用 -
host: localhost:6379
password:
maxIdle:
minIdle:
maxTotal:
maxWaitMillis: 5000
redis配置類:
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettucePoolingClientConfiguration;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.SerializationException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashSet;
import java.util.Set;
@Configuration
public class RedisConfiguration {
@Value("${spring.redis.cache.nodes:}")
private String nodes;
@Value("${spring.redis.cache.host:}")
private String host;
@Value("${spring.redis.cache.password:}")
private String password;
@Value("${spring.redis.cache.maxIdle:}")
private Integer maxIdle;
@Value("${spring.redis.cache.minIdle:}")
private Integer minIdle;
@Value("${spring.redis.cache.maxTotal:}")
private Integer maxTotal;
@Value("${spring.redis.cache.maxWaitMillis:}")
private Long maxWaitMillis;
@Bean
LettuceConnectionFactory lettuceConnectionFactory() {
// 連接池配置
GenericObjectPoolConfig poolConfig = new GenericObjectPoolConfig();
poolConfig.setMaxIdle(maxIdle == null ? 8 : maxIdle);
poolConfig.setMinIdle(minIdle == null ? 1 : minIdle);
poolConfig.setMaxTotal(maxTotal == null ? 8 : maxTotal);
poolConfig.setMaxWaitMillis(maxWaitMillis == null ? 5000L : maxWaitMillis);
LettucePoolingClientConfiguration lettucePoolingClientConfiguration = LettucePoolingClientConfiguration.builder()
.poolConfig(poolConfig)
.build();
// 單機redis
RedisStandaloneConfiguration redisConfig = new RedisStandaloneConfiguration();
redisConfig.setHostName(host==null||"".equals(host)?"localhost":host.split(":")[0]);
redisConfig.setPort(Integer.valueOf(host==null||"".equals(host)?"6379":host.split(":")[1]));
if (password != null && !"".equals(password)) {
redisConfig.setPassword(password);
}
// 哨兵redis
// RedisSentinelConfiguration redisConfig = new RedisSentinelConfiguration();
// 集群redis
/*RedisClusterConfiguration redisConfig = new RedisClusterConfiguration();
Set<RedisNode> nodeses = new HashSet<>();
String[] hostses = nodes.split("-");
for (String h : hostses) {
h = h.replaceAll("\\s", "").replaceAll("\n", "");
if (!"".equals(h)) {
String host = h.split(":")[0];
int port = Integer.valueOf(h.split(":")[1]);
nodeses.add(new RedisNode(host, port));
}
}
redisConfig.setClusterNodes(nodeses);
// 跨集群執行命令時要遵循的最大重定向數量
redisConfig.setMaxRedirects(3);
redisConfig.setPassword(password);*/
return new LettuceConnectionFactory(redisConfig, lettucePoolingClientConfiguration);
}
@Bean
public RedisTemplate<String, Object> redisTemplate(LettuceConnectionFactory lettuceConnectionFactory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(lettuceConnectionFactory);
//序列化類
MyRedisSerializer myRedisSerializer = new MyRedisSerializer();
//key序列化方式
template.setKeySerializer(myRedisSerializer);
//value序列化
template.setValueSerializer(myRedisSerializer);
//value hashmap序列化
template.setHashValueSerializer(myRedisSerializer);
return template;
}
static class MyRedisSerializer implements RedisSerializer<Object> {
@Override
public byte[] serialize(Object o) throws SerializationException {
return serializeObj(o);
}
@Override
public Object deserialize(byte[] bytes) throws SerializationException {
return deserializeObj(bytes);
}
/**
* 序列化
* @param object
* @return
*/
private static byte[] serializeObj(Object object) {
ObjectOutputStream oos = null;
ByteArrayOutputStream baos = null;
try {
baos = new ByteArrayOutputStream();
oos = new ObjectOutputStream(baos);
oos.writeObject(object);
byte[] bytes = baos.toByteArray();
return bytes;
} catch (Exception e) {
throw new RuntimeException("序列化失敗!", e);
}
}
/**
* 反序列化
* @param bytes
* @return
*/
private static Object deserializeObj(byte[] bytes) {
if (bytes == null){
return null;
}
ByteArrayInputStream bais = null;
try {
bais = new ByteArrayInputStream(bytes);
ObjectInputStream ois = new ObjectInputStream(bais);
return ois.readObject();
} catch (Exception e) {
throw new RuntimeException("反序列化失敗!", e);
}
}
}
} 上
現在就可以正常的使用redis了 示例
注入:
@Autowired private RedisTemplate<String, Object> redisTemplate;
添加:
redisTemplate.opsForValue().set(key, value);
添加,設置過期時間:
redisTemplate.opsForValue().set(key, obj, expireTime, TimeUnit.SECONDS);
獲取:
Object o = redisTemplate.opsForValue().get(key);
刪除:
redisTemplate.delete(key);
還可以根據自己需要編寫一個類RedisService,方便以後使用
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.concurrent.TimeUnit;
import static java.util.Objects.hash;
@Service
public class RedisService {
@Autowired
private RedisTemplate<String, Object> redis;
/**
* 添加
* @param key
* @param value
*/
@ResponseBody
public void set(String key,String value){
redis.opsForValue().set(key,value);
}
/**
* 添加並設置一個過期時間
* @param key
* @param value
* @param timeout 時間
* @param unit
* TimeUnit.DAYS //天
* TimeUnit.HOURS //小時
* TimeUnit.MINUTES //分鐘
* TimeUnit.SECONDS //秒
* TimeUnit.MILLISECONDS //毫秒
*/
public void set(String key, String value, long timeout,TimeUnit unit){
redis.opsForValue().set(key,value,timeout,unit);
}
/**
* 添加並設置一個過期時間默訂秒
* @param key
* @param value
* @param timeout 時間 秒
*/
public void set(String key, String value, long timeout){
redis.opsForValue().set(key,value,timeout,TimeUnit.SECONDS);
}
/**
* 將指定param的值設置為1,{@param param}會經過hash計算進行存儲。
*
* @param key bitmap結構的key
* @param param 要設置偏移的key,該key會經過hash運算。
* @param value true:即該位設置為1,否則設置為0
* @return 返回設置該value之前的值。
*/
public Boolean setBit(String key,String param,boolean value){
return redis.opsForValue().setBit(key,hash(param),value);
}
/**
* 獲取
* @param key
*/
public Object get(String key){
return redis.opsForValue().get(key);
}
/**
* 刪除
* @param key
*/
public void del(String key){
redis.delete(key);
}
/**
* 獲取key大小
* @param key bitmap結構的key
*/
public Long size(String key){
return redis.opsForValue().size(key);
}
}
注入:
@Autowired private RedisService redis;添
添加:
redis.set("usename","NX",9);//到期時間 秒
獲取:
redis.get("usename");

