在redis中,一个实例,默认有16个库,数据库名以序号命名0~15,可以根据业务需要的不同,把数据存储在不同序号的数据中。在实际应用中,该如何写配置文件,才能连接多个redis数据源呢,今天就来试一试。
在使用Redis之前,首先需要安装Redis数据库,没安装的可以参考SpringBoot初次集成Redis踩坑,安装+使用 一文,这里就不细说Redis的安装了。
本文基于SpringBoot2.1.4对Redis多数据源进行集成的。在集成的过程中用到了jedis client、Apache的commons-pool2、jackson-databind,以及spring-boot-starter-data-redis,在pom中需要把这些必须的架包引入;
org.springframework.boot
spring-boot-starter-web
com.alibaba
fastjson
1.2.62
org.springframework.boot
spring-boot-configuration-processor
true
org.apache.commons
commons-pool2
com.fasterxml.jackson.core
jackson-databind
org.springframework.boot
spring-boot-starter-data-redis
redis.clients
jedis
第二步,配置文件的配置;
import java.io.Serializable;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisStandaloneConfiguration;
import org.springframework.data.redis.connection.lettuce.LettuceClientConfiguration;
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.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
/**
* redis配置类
* @author 程就人生
* @date 2019年12月16日
*/
@Configuration
@EnableCaching//开启注解式缓存
public class RedisMoreDatasourceConfig extends CachingConfigurerSupport {
/**
* 配置lettuce连接池(多数据源的公共参数)
* GenericObjectPoolConfig不是线程安全的
* @return
*/
@SuppressWarnings("rawtypes")
@Bean
@ConfigurationProperties(prefix = "spring.redis.lettuce.pool")
public GenericObjectPoolConfig redisPool() {
return new GenericObjectPoolConfig<>();
}
/**
* 配置第一个数据源的
*
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.redis")
public RedisStandaloneConfiguration redisConfig() {
return new RedisStandaloneConfiguration();
}
/**
* 配置第二个数据源
*
* @return
*/
@Bean
@ConfigurationProperties(prefix = "spring.redis2")
public RedisStandaloneConfiguration redisConfig2() {
return new RedisStandaloneConfiguration();
}
/**
* 配置第一个数据源的连接工厂
* 这里注意:需要添加@Primary 指定bean的名称,目的是为了创建两个不同名称的LettuceConnectionFactory
*
* @param config
* @param redisConfig
* @return
*/
@SuppressWarnings("rawtypes")
@Bean("factory")
@Primary
public LettuceConnectionFactory factory(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfig) {
LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
return new LettuceConnectionFactory(redisConfig, clientConfiguration);
}
@SuppressWarnings("rawtypes")
@Bean("factory2")
public LettuceConnectionFactory factory2(GenericObjectPoolConfig config, RedisStandaloneConfiguration redisConfig2) {
LettuceClientConfiguration clientConfiguration = LettucePoolingClientConfiguration.builder().poolConfig(config).build();
return new LettuceConnectionFactory(redisConfig2, clientConfiguration);
}
/**
* 配置第一个数据源的RedisTemplate
* 注意:这里指定使用名称=factory 的 RedisConnectionFactory
* 并且标识第一个数据源是默认数据源 @Primary
*
* @param factory
* @return
*/
@Bean("redisTemplate")
@Primary
public RedisTemplate redisTemplate(@Qualifier("factory") RedisConnectionFactory factory) {
RedisTemplate template = new RedisTemplate<>();
template.setConnectionFactory(factory);
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setValueSerializer(new JdkSerializationRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(new JdkSerializationRedisSerializer());
//开启事务
template.setEnableTransactionSupport(true);
template.afterPropertiesSet();
return template;
}
/**
* 配置第一个数据源的RedisTemplate
* 注意:这里指定使用名称=factory2 的 RedisConnectionFactory
*
* @param factory2
* @return
*/
@SuppressWarnings({ "rawtypes", "unchecked" })
@Bean("redisTemplate2")
public RedisTemplate redisTemplate2(@Qualifier("factory2") RedisConnectionFactory factory2) {
RedisTemplate template = new RedisTemplate();
template.setConnectionFactory(factory2);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// key采用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
// hash的key也采用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
// value序列化方式采用jackson
template.setValueSerializer(jackson2JsonRedisSerializer);
// hash的value序列化方式采用jackson
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
}
第三步,properties文件里也需要对应的参数;
#Redis common param
spring.redis.lettuce.pool.max-idle=100
spring.redis.lettuce.pool.min-idle=50
spring.redis.lettuce.pool.max-wait=2000
cache.default-exp=72
#data 0
spring.redis.database=0
spring.redis.host=127.0.0.1
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=3000
#data 1
spring.redis2.database=1
spring.redis2.host=127.0.0.1
spring.redis2.port=6379
spring.redis2.password=
spring.redis2.timeout=3000
第四步,测试代码;
import com.alibaba.fastjson.JSONObject;
@RestController
public class IndexController {
/**
* 第一个数据源对应的template
*/
@Autowired
private RedisTemplate redisTemplate;
/**
* 第二个数据源对应的template
*/
@Autowired
@Qualifier("redisTemplate2")
private RedisTemplate redisTemplate2;
//测试
@GetMapping("/index")
public void index(){
//数据库0,数据的存储及取出
redisTemplate.opsForValue().set("aa", "aaaaa");
String aa = (String) redisTemplate.opsForValue().get("aa");
System.out.println(aa);
//数据库1,数据的存储及取出
JSONObject json = new JSONObject();
json.put("aa", "bbbbbb");
redisTemplate2.opsForHash().put("cc", "aa", json);
json = (JSONObject) redisTemplate2.opsForHash().get("cc", "aa");
System.out.println(json.toJSONString());
}
}
最后,测试;启动入口程序,在浏览器上输出Controller的地址,从控制台可以看到测试的结果;
为了保险起见,还是去客户端查看一下存储的结果吧。
在做这个demo时,遇到了一些问题及总结;
- 把配置文件的类名命名为RedisConfig,在项目启动时会报bean名重复,这是因为和配置文件里的bean名重复了,这是需要注意的地方;
- 在RedisStandaloneConfiguration类中,默认的host是localhost,port是6379,database默认的是0,password默认无,这些都可以通过RedisStandaloneConfiguration的源码找到,在配置文件里没有时,就会使用默认的参数;
- 在RedisConnectionFactory接口里,getConnection()有两种实现方式,一种是JedisConnectionFactory,一种是LettuceConnectionFactory,本文的示例中使用的是后一种,这个可以根据个人喜好进行选择;
- 不管有几个数据源,最好配置一个@Primary数据源;在使用RedisTemplate时,如果不用@Qualifier注解指明,则使用默认的数据源。