前要
手头有个项目会用到查询redis同数据源不同database的情况,在网上找了一堆方法感觉在多线程高并发下都会有一些问题。由此,自己研究出了此种方法希望能帮助到大家。
话不多说下面贴代码了开始 O(∩_∩)O哈哈~
自定义RedisProperties
自定义redisProperties实现添加dbList项
package com.dong.base.redis.core;
import org.apache.commons.lang3.StringUtils;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import java.util.List;
/**
* 自定义redis 配置类
* @author 王少东
*/
public class MyRedisProperties extends RedisProperties {
// 需要操作的db
private String dbList;
public String[] getDbList() {
if (StringUtils.isEmpty(dbList)) {
return null;
}
String[] list = dbList.split(",");
return list;
}
public void setDbList(String dbList) {
this.dbList = dbList;
}
}
自定义StringRedisTemplate
自定义SringRedisTemplate实现存储待操作的db的redisTemplate列表
package com.dong.base.redis.core;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import lombok.Data;
import org.apache.commons.lang3.StringUtils;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;
import java.util.HashMap;
import java.util.Map;
/**
* 自定义StringRedisTemplate类
* @author 王少东
*/
@Data
public class MyStringRedisTemplate extends StringRedisTemplate {
// 需要切换db的StringRedisTemplate 的 map
private Map redisTemplateMap = new HashMap();
// 需要切换db的ClientResources
private ClientResources dbListClientResources;
// 需要切换db的MyRedisProperties
private MyRedisProperties dbListProperties;
public MyStringRedisTemplate(){
}
public MyStringRedisTemplate(MyRedisProperties properties){
this(properties,DefaultClientResources.create());
}
public MyStringRedisTemplate(MyRedisProperties properties, ClientResources clientResources){
this(properties,clientResources,null);
}
public MyStringRedisTemplate(MyRedisProperties properties, ClientResources clientResources,RedisConnectionFactory redisConnectionFactory){
this.dbListProperties = properties;
this.dbListClientResources = clientResources;
if (redisConnectionFactory != null) {
this.setConnectionFactory(redisConnectionFactory);
}
this.buildMoreDbStringRedisTemple();
}
/**
* 获取某个数据库的RedisTemplate
* @param dbIndex
* @return
*/
public StringRedisTemplate getDbStringRedisTemplate(String dbIndex) {
StringRedisTemplate template = this.redisTemplateMap.get(dbIndex);
Assert.isTrue(template != null, dbIndex + "库不存在!");
return template;
}
public StringRedisTemplate getDbStringRedisTemplate(int dbIndex) {
return getDbStringRedisTemplate(String.valueOf(dbIndex));
}
// 构建待切换db列表
private void buildMoreDbStringRedisTemple () {
if (dbListProperties != null )
if (this.dbListProperties.getDbList() != null && this.dbListProperties.getDbList().length > 0) {
for (String db : this.dbListProperties.getDbList()) {
Assert.isTrue(StringUtils.isNumeric(db), "redis 配置的dblist 必须是数字!");
// 当默认和默认db一样的时候设置类本身
if (db.equals(String.valueOf(this.dbListProperties.getDatabase()))) {
redisTemplateMap.put(db,this);
continue;
}
StringRedisTemplate template = new StringRedisTemplate();
// 构建 LettuceConnectionFactory 连接池
LettuceConnectionFactory lettuceConnectionFactory = BuildRedisConfig.buildLettuceConnectionFactory(Integer.valueOf(db), dbListClientResources,this.dbListProperties);
template.setConnectionFactory(lettuceConnectionFactory);
lettuceConnectionFactory.afterPropertiesSet();
template.afterPropertiesSet();
redisTemplateMap.put(db,template);
}
}
}
}
BuildRedisConfig类
BuildRedisConfig是一个构建LettuceConnectionFactory的工具类
package com.dong.base.redis.core;
import io.lettuce.core.resource.ClientResources;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.data.redis.connection.RedisPassword;
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;
/**
* 公共构建redis BuildRedisConfig的类
* @author 王少东
*/
public class BuildRedisConfig {
/**
* 构建LettuceConnectionFactory的方法
* @param clientResources
* @param properties
* @return
*/
public static LettuceConnectionFactory buildLettuceConnectionFactory(ClientResources clientResources, RedisProperties properties){
return buildLettuceConnectionFactory(-1,clientResources, properties );
}
/**
* 构建LettuceConnectionFactory的方法
* @param clientResources
* @param properties
* @return
*/
public static LettuceConnectionFactory buildLettuceConnectionFactory(int dbIndex, ClientResources clientResources, RedisProperties properties){
RedisStandaloneConfiguration redis1StandaloneConfiguration = getStandaloneConfig(dbIndex, properties);
LettuceClientConfiguration clientConfig = getLettuceClientConfiguration(clientResources, properties);
return new LettuceConnectionFactory(redis1StandaloneConfiguration, clientConfig);
}
/**
* redis standalone config
*
* @param redisProperties redis 配置参数
* @return RedisStandaloneConfiguration
*/
private static RedisStandaloneConfiguration getStandaloneConfig(int dbIndex, RedisProperties redisProperties) {
RedisStandaloneConfiguration config = new RedisStandaloneConfiguration();
config.setHostName(redisProperties.getHost());
config.setPort(redisProperties.getPort());
config.setPassword(RedisPassword.of(redisProperties.getPassword()));
config.setDatabase(dbIndex > -1 ? dbIndex : redisProperties.getDatabase());
return config;
}
/**
* redis standalone config
*
* @param redisProperties redis 配置参数
* @return RedisStandaloneConfiguration
*/
private static RedisStandaloneConfiguration getStandaloneConfig(RedisProperties redisProperties) {
return getStandaloneConfig(-1, redisProperties);
}
/**
* 构建 LettuceClientConfiguration
*
* @param clientResources clientResources
* @param redisProperties redisProperties
* @return LettuceClientConfiguration
*/
private static LettuceClientConfiguration getLettuceClientConfiguration(ClientResources clientResources,
RedisProperties redisProperties) {
LettuceClientConfiguration.LettuceClientConfigurationBuilder builder =
createBuilder(redisProperties.getLettuce().getPool());
if (redisProperties.isSsl()) {
builder.useSsl();
}
if (redisProperties.getTimeout() != null) {
builder.commandTimeout(redisProperties.getTimeout());
}
if (redisProperties.getLettuce() != null) {
RedisProperties.Lettuce lettuce = redisProperties.getLettuce();
if (lettuce.getShutdownTimeout() != null
&& !lettuce.getShutdownTimeout().isZero()) {
builder.shutdownTimeout(
redisProperties.getLettuce().getShutdownTimeout());
}
}
builder.clientResources(clientResources);
return builder.build();
}
/**
* 创建 LettuceClientConfigurationBuilder
*
* @param pool 连接池配置
* @return LettuceClientConfigurationBuilder
*/
private static LettuceClientConfiguration.LettuceClientConfigurationBuilder createBuilder(RedisProperties.Pool pool) {
if (pool == null) {
return LettuceClientConfiguration.builder();
}
return LettucePoolingClientConfiguration.builder()
.poolConfig(getPoolConfig(pool));
}
/**
* pool config
*
* @param properties redis 参数配置
* @return GenericObjectPoolConfig
*/
private static GenericObjectPoolConfig getPoolConfig(RedisProperties.Pool properties) {
GenericObjectPoolConfig config = new GenericObjectPoolConfig();
config.setMaxTotal(properties.getMaxActive());
config.setMaxIdle(properties.getMaxIdle());
config.setMinIdle(properties.getMinIdle());
if (properties.getMaxWait() != null) {
config.setMaxWaitMillis(properties.getMaxWait().toMillis());
}
return config;
}
}
RedisConfig 配置类
package com.dong.base.redis.config;
import com.dong.base.redis.core.BuildRedisConfig;
import com.dong.base.redis.core.MyRedisProperties;
import com.dong.base.redis.core.MyStringRedisTemplate;
import io.lettuce.core.resource.ClientResources;
import io.lettuce.core.resource.DefaultClientResources;
import lombok.Getter;
import lombok.Setter;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.data.redis.RedisProperties;
import org.springframework.boot.context.properties.ConfigurationProperties;
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.RedisPassword;
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.StringRedisTemplate;
@Configuration
@ConfigurationProperties(prefix = "spring.redis")
@Getter
@Setter
public class RedisConfig {
private MyRedisProperties master;
private MyRedisProperties cache;
@Bean(destroyMethod = "shutdown")
@ConditionalOnMissingBean(ClientResources.class)
public DefaultClientResources lettuceClientResources() {
return DefaultClientResources.create();
}
@Bean(name = "redisTemplateMaster")
@Primary
public MyStringRedisTemplate stringRedisTemplate1(
@Qualifier("RedisConnectionFactoryMaster") RedisConnectionFactory redisConnectionFactory,ClientResources clientResources) {
// StringRedisTemplate template = new StringRedisTemplate();
// template.setConnectionFactory(redisConnectionFactory);
MyStringRedisTemplate template = new MyStringRedisTemplate(master,clientResources,redisConnectionFactory);
return template;
}
@Bean(name = "RedisConnectionFactoryMaster")
@Primary
public LettuceConnectionFactory Redis1LettuceConnectionFactory(ClientResources clientResources) {
return BuildRedisConfig.buildLettuceConnectionFactory(clientResources,master);
}
@Bean(name = "redisTemplateCache")
public MyStringRedisTemplate stringRedisTemplate2(
@Qualifier("RedisConnectionFactoryCache") RedisConnectionFactory redisConnectionFactory) {
MyStringRedisTemplate template = new MyStringRedisTemplate();
template.setConnectionFactory(redisConnectionFactory);
return template;
}
@Bean(name = "RedisConnectionFactoryCache")
public LettuceConnectionFactory Redis2LettuceConnectionFactory(ClientResources clientResources) {
return BuildRedisConfig.buildLettuceConnectionFactory(clientResources,cache);
}
}
application.yml配置文件
在原来的默认redis配置文件中加入了dbList配置字,此处我用到了多数据源自行更改
spring:
redis:
master:
# redis 持久化地址
host: 127.0.0.1
port: 6379
password: 123132
database: 15
dbList: 0,1,2,3,4,5,6,7,8,9
cache:
# redis 缓存库的地址
host: 127.0.0.1
port: 7379
password: 1231
database: 0
用法
MyStringRedisTemplate 直接操作走的默认数据(注:就是database配置)
MyStringRedisTemplate.getDbStringRedisTemplate(5)获取到需要操作的db的redisTemplate再去操作redis。