java连接腾讯云上的redis
腾讯云上的配置
在安全组上打开相关的端口即可
"来源" 就是你的目标服务器的 ip(也可以是 0.0.0.0/0) 协议端口可以用范围的写法 TCP:6379-6389
然后需将 redis 运行使用的配置文件 redis.conf 默认 bind 127.0.0.1(只允许本地访问)注释掉 (或者改为 0.0.0.0)
# bind 127.0.0.1
protected-mode no 从yes改为no
redis 连接单机和集群
依赖 pom.xml
<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>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.2</version>
</dependency>
redis 参数的配置文件
redis.properties
#启动集群
#redis.cluster=true
########################### reids 单机配置 ##############################
#Matser 的 ip 地址
redis.host=49.235.196.22
#端口号
redis.port=6380
#如果有密码
#redis.password=
#客户端超时时间单位是毫秒 默认是 2000
redis.timeout=5000
########################### jedis单机与集群的公共配置 ##############################
#最大空闲数
redis.maxIdle=300
#连接池的最大数据库连接数。设为 0 表示无限制, 如果是 jedis 2.4 以后用 redis.maxTotal
#redis.maxActive=600
#控制一个 pool 可分配多少个 jedis 实例, 用来替换上面的 redis.maxActive, 如果是 jedis 2.4 以后用该属性
redis.maxTotal=1000
#最大建立连接等待时间。如果超过此时间将接到异常。设为 -1 表示无限制。
redis.maxWaitMillis=1000
#连接的最小空闲时间 默认 1800000 毫秒 (30 分钟)
redis.minEvictableIdleTimeMillis=300000
#每次释放连接的最大数目, 默认 3
redis.numTestsPerEvictionRun=1024
#逐出扫描的时间间隔 (毫秒) 如果为负数, 则不运行逐出线程, 默认 -1
redis.timeBetweenEvictionRunsMillis=30000
#是否在从池中取出连接前进行检验, 如果检验失败, 则从池中去除连接并尝试取出另一个
redis.testOnBorrow=true
#在空闲时检查有效性, 默认 false
redis.testWhileIdle=true
########################### redis 集群配置 ##############################
redis.clusterNodes=49.235.196.22:7001,49.235.196.22:7002,49.235.196.22:7003,49.235.196.22:7004,49.235.196.22:7005,49.235.196.22:7006
redis.maxRedirects=3
#哨兵模式
#redis.sentinel.host1=192.168.177.128
#redis.sentinel.port1=26379
#redis.sentinel.host2=172.20.1.231
#redis.sentinel.port2=26379
application.yml
redis:
cluster:
true
三个 Redis 的配置类,RedisConfig:集群和单机的公共部分,SinglenRedisConfig 单机特有的配置,ClusterRedisConfig 集群特有的配置
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
/**
-
Create by IntelliJ Idea 2018.2
-
@author: qyp
-
Date: 2019-09-29 17:15
*/
@Getter
@Setter
public abstract class RedisConfig {
/**
- 最大空闲数
*/
public Integer maxIdle;
/**
- 控制一个 pool 可分配多少个 jedis 实例
*/
public Integer maxTotal;
/**
- 最大建立连接等待时间。如果超过此时间将接到异常。设为 -1 表示无限制。
*/
public Integer maxWaitMillis;
/**
- 连接的最小空闲时间 默认 1800000 毫秒 (30 分钟)
*/
public Integer minEvictableIdleTimeMillis;
/**
- 每次释放连接的最大数目, 默认 3
*/
public Integer numTestsPerEvictionRun;
/**
- 逐出扫描的时间间隔 (毫秒) 如果为负数, 则不运行逐出线程, 默认 -1
*/
public long timeBetweenEvictionRunsMillis;
/**
- 是否在从池中取出连接前进行检验, 如果检验失败, 则从池中去除连接并尝试取出另一个
*/
public boolean testOnBorrow;
/**
- 在空闲时检查有效性, 默认 false
*/
public boolean testWhileIdle;
/**
- JedisPoolConfig 连接池
- @return
*/
@Bean
public JedisPoolConfig jedisPoolConfig() {
JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
// 最大空闲数
jedisPoolConfig.setMaxIdle(maxIdle);
// 连接池的最大数据库连接数
jedisPoolConfig.setMaxTotal(maxTotal);
// 最大建立连接等待时间
jedisPoolConfig.setMaxWaitMillis(maxWaitMillis);
// 逐出连接的最小空闲时间 默认 1800000 毫秒 (30 分钟)
jedisPoolConfig.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
// 每次逐出检查时 逐出的最大数目 如果为负数就是 : 1/abs(n), 默认 3
jedisPoolConfig.setNumTestsPerEvictionRun(numTestsPerEvictionRun);
// 逐出扫描的时间间隔 (毫秒) 如果为负数, 则不运行逐出线程, 默认 -1
jedisPoolConfig.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);
// 是否在从池中取出连接前进行检验, 如果检验失败, 则从池中去除连接并尝试取出另一个
jedisPoolConfig.setTestOnBorrow(testOnBorrow);
// 在空闲时检查有效性, 默认 false
jedisPoolConfig.setTestWhileIdle(testWhileIdle);
return jedisPoolConfig;
}
/**
- 单机构建 JedisConnectionFactory 对象
- @param jedisPoolConfig
- @return
*/
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
return null;
}
/**
-
集群 redis 构建 JedisConnectionFactory 对象
-
@param jedisPoolConfig
-
@param redisClusterConfiguration
-
@return
*/
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
return null;
}
/**
- 实例化 RedisTemplate 对象
- @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
initDomainRedisTemplate(redisTemplate, redisConnectionFactory);
return redisTemplate;
}
/**
- 设置数据存入 redis 的序列化方式, 并开启事务
- @param redisTemplate
- @param factory
*/
public void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate, RedisConnectionFactory factory) {
// 如果不配置 Serializer,那么存储的时候缺省使用 String,如果用 User 类型存储,那么会提示错误 User can't cast to String!
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
redisTemplate.setValueSerializer(new GenericJackson2JsonRedisSerializer());
// 开启事务
//redisTemplate.setEnableTransactionSupport(true);
redisTemplate.setConnectionFactory(factory);
}
}
SinglenRedisConfig.java
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import redis.clients.jedis.JedisPoolConfig;
/**
PropertySource 加载文件到当前类上下文的 Environment 中
*/
public class SinglenRedisConfig extends RedisConfig {/**
- host,port,timeout
- 这三个是单机属性
*/
private String host;
private Integer port;
private Integer timeout;
/**
-
单机版配置
-
@param @param jedisPoolConfig
-
@param @return
-
@return JedisConnectionFactory
-
@throws
-
@Title: JedisConnectionFactory
-
@autor lpl
@date 2018 年 2 月 24 日
*/
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig) {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory();
// 连接池
redisConnectionFactory.setPoolConfig(jedisPoolConfig);
//IP 地址
redisConnectionFactory.setHostName(host);
// 端口号
redisConnectionFactory.setPort(port);
// 如果 Redis 设置有密码
//JedisConnectionFactory.setPassword(password);// 客户端超时时间单位是毫秒
redisConnectionFactory.setTimeout(timeout);
return redisConnectionFactory;
}
}
ClusterRedisConfig.java
package per.qiao.config;
import lombok.Getter;
import lombok.Setter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.stereotype.Component;
import redis.clients.jedis.JedisPoolConfig;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
/**
-
@author qiao
*/
@Configuration
@PropertySource("classpath:redis.properties")
//@EnableConfigurationProperties(ClusterRedisConfig.class)
@ConfigurationProperties(prefix = "redis")
//@ConditionalOnExpression("#{'true'.equals(environment['redis.cluster'])}")
//@ConditionalOnExpression("'${redis.cluster}'=='true'")
@ConditionalOnExpression("${redis.cluster}")
@Getter
@Setter
public class ClusterRedisConfig extends RedisConfig {
/**
- clusterNodes,mmaxRedirectsac
- 这两个是集群属性
*/
private List<String> clusterNodes;
private Integer maxRedirects;
/**
-
Redis 集群的配置
-
@return RedisClusterConfiguration
-
@throws
-
@autor lpl
-
@date 2017 年 12 月 22 日
*/
@Bean
public RedisClusterConfiguration redisClusterConfiguration() {
RedisClusterConfiguration redisClusterConfiguration = new RedisClusterConfiguration();
Set<RedisNode> nodes = clusterNodes.stream().map(ipPort -> {
String[] ipAndPort = ipPort.split(":");
return new RedisNode(ipAndPort[0].trim(), Integer.valueOf(ipAndPort[1]));
}).collect(Collectors.toSet());
redisClusterConfiguration.setClusterNodes(nodes);
redisClusterConfiguration.setMaxRedirects(maxRedirects);
return redisClusterConfiguration;
}
/**
-
配置工厂
-
@param @param jedisPoolConfig
-
@param @return
-
@return JedisConnectionFactory
-
@throws
-
@Title: JedisConnectionFactory
-
@autor lpl
-
@date 2017 年 12 月 22 日
*/
@Bean
public JedisConnectionFactory redisConnectionFactory(JedisPoolConfig jedisPoolConfig, RedisClusterConfiguration redisClusterConfiguration) {
JedisConnectionFactory redisConnectionFactory = new JedisConnectionFactory(redisClusterConfiguration, jedisPoolConfig);
return redisConnectionFactory;
}
}
测试
@SpringBootTest
@RunWith(SpringRunner.class)
public class RedisTest {
<span class="hljs-meta">@Autowired</span>
RedisUtil redisUtil;
<span class="hljs-meta">@Test</span>
<span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title function_">test</span><span class="hljs-params">()</span> {
<span class="hljs-comment">//redisUtil.del("abc");</span>
redisUtil.set(<span class="hljs-string">"abc"</span>, <span class="hljs-string">"1234567"</span>);
System.out.println(<span class="hljs-string">"================"</span>);
<span class="hljs-type">Object</span> <span class="hljs-variable">myKey</span> <span class="hljs-operator">=</span> redisUtil.get(<span class="hljs-string">"abc"</span>);
System.out.println(myKey);
}
}
遗留问题
问题 1:在集群配置上出了个问题 ClusterRedisConfig
问题一、使用@PropertySource("classpath:redis.properties")加载配置文件,然后使用@ConditionalOnExpression获取不到配置文件中的值
使用@PropertySource("classpath:redis.properties")加载指定的属性文件, 然后使用@ConfigurationProperties(prefix = "redis")指定前缀,最后使用@ConditionalOnExpression("${redis.cluster}")判断是否加载当前类
但是这个判断不能按照设想进行控制。
1. 当我将属性 redis.cluster 放到 redis.properties 中时,获取不到值,抛 there is still more data in the expression in 'lcurly({)'错误
2. 当我把属性 redis.cluster 放到 application.yml 文件中时,是可以成功的。
猜想:yml 文件最先加载,@ConditionalOnExpression又比@PropertySource先加载,所以拿不到数据
问题 2:在使用 lettuce 连接 redis 时,项目总是报集群的连接超时,但是项目可以正常使用
这是使用 lettuce(生菜) 连接的 yml 配置文件
spring:
redis:
database: 1
# host:
# port:
# password:
cluster:
nodes:
- 49.235.196.22:7001
- 49.235.196.22:7002
- 49.235.196.22:7003
- 49.235.196.22:7004
- 49.235.196.22:7005
- 49.235.196.22:7006
lettuce:
pool:
# 连接池最大连接数 默认 8 ,负数表示没有限制
max-active: 8
# 连接池中的最大空闲连接 默认 8
max-idle: 8
# 连接池中的最小空闲连接 默认 0
min-idle: 0
# 连接池最大阻塞等待时间(使用负值表示没有限制) 默认 -1
max-wait: -1s
host: 49.235.196.22
port: 7001
#timeout: 30000s
这是配置类
@Configuration
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig2 {
<span class="hljs-comment">/**
* springboot2.x 使用LettuceConnectionFactory 代替 RedisConnectionFactory
* application.yml配置基本信息后,springboot2.x RedisAutoConfiguration能够自动装配
* LettuceConnectionFactory 和 RedisConnectionFactory 及其 RedisTemplate
* <span class="hljs-doctag">@param</span> redisConnectionFactory
* <span class="hljs-doctag">@return</span>
*/</span>
<span class="hljs-meta">@Bean</span>
<span class="hljs-keyword">public</span> RedisTemplate<String, Object> <span class="hljs-title function_">redisTemplate</span><span class="hljs-params">(LettuceConnectionFactory redisConnectionFactory)</span>{
RedisTemplate<String, Object> redisTemplate = <span class="hljs-keyword">new</span> <span class="hljs-title class_">RedisTemplate</span><String, Object>();
redisTemplate.setKeySerializer(<span class="hljs-keyword">new</span> <span class="hljs-title class_">StringRedisSerializer</span>());
redisTemplate.setValueSerializer(<span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericJackson2JsonRedisSerializer</span>());
redisTemplate.setHashKeySerializer(<span class="hljs-keyword">new</span> <span class="hljs-title class_">StringRedisSerializer</span>());
redisTemplate.setHashValueSerializer(<span class="hljs-keyword">new</span> <span class="hljs-title class_">GenericJackson2JsonRedisSerializer</span>());
redisTemplate.setConnectionFactory(redisConnectionFactory);
<span class="hljs-keyword">return</span> redisTemplate;
}
}