Springboot整合redis切库问题

切库问题

由于工作业务需求,需要在单机redis中做切库处理。一般来说,redis数据库有16个数据库,而且有对应的索引,分别为0-15,如下图
Springboot整合redis切库问题_第1张图片
目前的项目时Springboot2.0.5搭建的,当前已经有一个redis工具类了。但是不满足需求,需要修改。

旧版RedisUtils

application.yml配置

spring:
  redis:
    open: true  # 是否开启redis缓存  true开启   false关闭
    database: 0
    host: localhost
    port: 6379
    password:    # 密码(默认为空)
    timeout: 6000ms  # 连接超时时长(毫秒)
    jedis:
      pool:
        max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms      # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 10      # 连接池中的最大空闲连接
        min-idle: 5       # 连接池中的最小空闲连接

redis配置类

@Configuration
public class RedisConfig {
    @Autowired
    private RedisConnectionFactory factory;

    @Bean
    public RedisTemplate redisTemplate() {
        RedisTemplate redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        return redisTemplate;
    }

    @Bean
    public HashOperations hashOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations valueOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public ListOperations listOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForList();
    }

    @Bean
    public SetOperations setOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations zSetOperations(RedisTemplate redisTemplate) {
        return redisTemplate.opsForZSet();
    }

RedisUtils

@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate redisTemplate;
    @Resource(name="redisTemplate")
    private ValueOperations valueOperations;
    @Resource(name="redisTemplate")
    private HashOperations hashOperations;
    @Resource(name="redisTemplate")
    private ListOperations listOperations;
    @Resource(name="redisTemplate")
    private SetOperations setOperations;
    @Resource(name="redisTemplate")
    private ZSetOperations zSetOperations;
    /**  默认过期时长,单位:秒 */
    public final static long DEFAULT_EXPIRE = 60 * 60 * 24;
    /**  不设置过期时长 */
    public final static long NOT_EXPIRE = -1;

    public void set(String key, Object value, long expire){
        valueOperations.set(key, toJson(value));
        if(expire != NOT_EXPIRE){
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
    }

    public void set(String key, Object value){
        set(key, value, DEFAULT_EXPIRE);
    }

    public  T get(String key, Class clazz, long expire) {
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE){
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value == null ? null : fromJson(value, clazz);
    }

    public  T get(String key, Class clazz) {
        return get(key, clazz, NOT_EXPIRE);
    }

    public String get(String key, long expire) {
        String value = valueOperations.get(key);
        if(expire != NOT_EXPIRE){
            redisTemplate.expire(key, expire, TimeUnit.SECONDS);
        }
        return value;
    }

    public String get(String key) {
        return get(key, NOT_EXPIRE);
    }

    public void delete(String key) {
        redisTemplate.delete(key);
    }

    /**
     * Object转成JSON数据
     */
    private String toJson(Object object){
        if(object instanceof Integer || object instanceof Long || object instanceof Float ||
                object instanceof Double || object instanceof Boolean || object instanceof String){
            return String.valueOf(object);
        }
        return JSON.toJSONString(object);
    }

    /**
     * JSON数据,转成Object
     */
    private  T fromJson(String json, Class clazz){
        return JSON.parseObject(json, clazz);
    }

Redis切面,用来控制redis开关

@Aspect
@Component
public class RedisAspect {
    private Logger logger = LoggerFactory.getLogger(getClass());
    //是否开启redis缓存  true开启   false关闭
    @Value("${renren.redis.open}")
    private boolean open;

    @Around("execution(* io.renren.common.utils.RedisUtils.*(..))")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object result = null;
        if(open){
            try{
                result = point.proceed();
            }catch (Exception e){
                logger.error("redis error", e);
                throw new RRException("Redis服务异常");
            }
        }
        return result;
    }

以上是最开始的redis工具,但是只能在yml配置文件中配置指定的库,不能动态切库。

首次尝试

参照了这篇文章
spring-data-redis进行选库操作
我自定义了redisTemplate,继承StringRedisTemplate,然后重写了protected RedisConnection方法,然后整合当前的工具类,做了一些修改。但是最后测试的时候报错:

java.lang.UnsupportedOperationException: Selecting a new database not supported due to shared connection. Use separate ConnectionFactorys to work with multiple databases
	at org.springframework.data.redis.connection.lettuce.LettuceConnection.select(LettuceConnection.java:640)
	at com.xQuant.app.common.utils.RedisUtils.setDbIndex(RedisUtils.java:45)
	at com.xQuant.app.common.utils.RedisUtils.set(RedisUtils.java:49)
	at com.xQuant.app.common.utils.RedisUtils.set(RedisUtils.java:57)
	at com.xQuant.app.XQuantAppApplicationTests.contextLoads(XQuantAppApplicationTests.java:20)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
	at org.springframework.test.context.junit4.statements.RunBeforeTestExecutionCallbacks.evaluate(RunBeforeTestExecutionCallbacks.java:73)
	at org.springframework.test.context.junit4.statements.RunAfterTestExecutionCallbacks.evaluate(RunAfterTestExecutionCallbacks.java:83)
	at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
	at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
	at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
	at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
	at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:89)
	at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:41)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:541)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:763)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:463)
	at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:209)


  • 大概意思就是在共享链接情况下不能切换库。

方案一,还是用RedisTemplate

同事在网上找到了一篇这个文章:
Spring cloud 和 Spring Boot 升级到F版和2.x遇到的问题。
这里面有提到遇到上面那个问题:
Springboot整合redis切库问题_第2张图片
给出的解决方案是在实例化RedisTemplate时,不再注入RedisConnectionFactory,改为注入LettuceConnectionFactory ,并关闭共享链接。所以修改当前的redis配置和工具类:
修改后的Redis配置

@Configuration
public class RedisConfig {
	@Autowired
	private LettuceConnectionFactory factory;

	@Bean
	public RedisTemplate redisTemplate() {
		// 关闭共享链接
		factory.setShareNativeConnection(false);
		RedisTemplate redisTemplate = new RedisTemplate<>();
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashKeySerializer(new StringRedisSerializer());
		redisTemplate.setHashValueSerializer(new StringRedisSerializer());
		redisTemplate.setValueSerializer(new StringRedisSerializer());
		redisTemplate.setConnectionFactory(factory);
		return redisTemplate;
	}

	@Bean
	public HashOperations hashOperations(RedisTemplate redisTemplate) {
		return redisTemplate.opsForHash();
	}

	@Bean
	public ValueOperations valueOperations(RedisTemplate redisTemplate) {
		return redisTemplate.opsForValue();
	}

	@Bean
	public ListOperations listOperations(RedisTemplate redisTemplate) {
		return redisTemplate.opsForList();
	}

	@Bean
	public SetOperations setOperations(RedisTemplate redisTemplate) {
		return redisTemplate.opsForSet();
	}

	@Bean
	public ZSetOperations zSetOperations(RedisTemplate redisTemplate) {
		return redisTemplate.opsForZSet();
	}

主要修改了两个地方,注入LettuceConnectionFactory ,关闭共享链接
修改后的RedisUtils

/**
 * Redis工具类
 * 
 * 封装了对象和字符串的存,取,删除,设置过期时间操作. 所有操作可以指定数据库索引. 存,取可以设置过期时间. 没有设置默认过期时间,存值时尽量设置过期时间
 * 
 * @author chunhui.tan
 * @version 创建时间:2018年10月8日 下午3:31:00
 */
@Component
public class RedisUtils {
	@Autowired
	private RedisTemplate redisTemplate;
	@Autowired
	private ValueOperations valueOperations;
	@Autowired
	private HashOperations hashOperations;
	@Autowired
	private ListOperations listOperations;
	@Autowired
	private SetOperations setOperations;
	@Autowired
	private ZSetOperations zSetOperations;
	/** 默认过期时长,单位:秒 */
	//public final static long DEFAULT_EXPIRE = 60 * 60 * 24;
	/** 不设置过期时长 */
	public final static long NOT_EXPIRE = -1;
	private final static Gson gson = new Gson();
	
	public RedisTemplate getRedisTemplate() {
		return redisTemplate;
	}

	/**
	 * 插入值-对象,指定数据库索引,指定过期时间
	 * 
	 * @param key     键
	 * @param value   值
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 */
	public void set(String key, Object value, Integer dbIndex, long expire) {
		// 选择数据库
		setDbIndex(dbIndex);
		valueOperations.set(key, toJson(value));
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
	}

	/**
	 * 插入值-对象
	 * 
	 * @param key     键
	 * @param value   值
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 */
	public void set(String key, Object value, Integer dbIndex) {
		set(key, value, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 插入值-对象 ,默认0 index数据库
	 * 
	 * @param key   键
	 * @param value 值
	 */
	public void set(String key, Object value) {
		set(key, value, 0, NOT_EXPIRE);
	}

	/**
	 * 获取值-对象,指定数据库索引,并设置过期时间
	 * 
	 * @param key     键
	 * @param clazz   字节码对象
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 * @return
	 */
	public  T get(String key, Class clazz, Integer dbIndex, long expire) {
		setDbIndex(dbIndex);
		String value = valueOperations.get(key);
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		return value == null ? null : fromJson(value, clazz);
	}

	/**
	 * 取值-对象 指定数据库索引
	 * 
	 * @param key     键
	 * @param clazz   字节码对象
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @return
	 */
	public  T get(String key, Class clazz, Integer dbIndex) {
		return get(key, clazz, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-对象
	 * 
	 * @param key   键
	 * @param clazz 字节码对象
	 * @return
	 */
	public  T get(String key, Class clazz) {
		return get(key, clazz, 0, NOT_EXPIRE);
	}

	/**
	 * 获取值-字符串,指定数据库索引,设置过期时间
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 * @return
	 */
	public String get(String key, Integer dbIndex, long expire) {
		setDbIndex(dbIndex);
		String value = valueOperations.get(key);
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
		return value;
	}

	/**
	 * 取值-字符串,指定数据库索引
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @return
	 */
	public String get(String key, Integer dbIndex) {
		return get(key, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-字符串
	 * 
	 * @param key 键
	 * @return
	 */
	public String get(String key) {
		return get(key, 0, NOT_EXPIRE);
	}

	/**
	 * 删除 指定数据库索引
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 */
	public Boolean delete(String key, Integer dbIndex) {
		setDbIndex(dbIndex);
		return redisTemplate.delete(key);
	}

	/**
	 * 删除
	 * 
	 * @param key 键
	 */
	public Boolean delete(String key) {
		return delete(key, 0);
	}

	/**
	 * 设置过期时间 ,指定数据库索引
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 */
	public void expire(String key, Integer dbIndex, int expire) {
		setDbIndex(dbIndex);
		if (expire != NOT_EXPIRE) {
			redisTemplate.expire(key, expire, TimeUnit.SECONDS);
		}
	}

	/**
	 * 设置过期时间
	 * 
	 * @param key    键
	 * @param expire 过期时间 单位:秒
	 */
	public void expire(String key, int expire) {
		expire(key, 0, expire);
	}

	/**
	 * Object转成JSON数据
	 */
	private String toJson(Object object) {
		if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double
				|| object instanceof Boolean || object instanceof String) {
			return String.valueOf(object);
		}
		return gson.toJson(object);

	}

	/**
	 * JSON数据,转成Object
	 */
	private  T fromJson(String json, Class clazz) {
		return gson.fromJson(json, clazz);

	}

	/**
	 * 设置数据库索引
	 * 
	 * @param dbIndex
	 */
	private void setDbIndex(Integer dbIndex) {
		if (dbIndex == null || dbIndex > 15 || dbIndex < 0) {
			dbIndex = 0;
		}
		LettuceConnectionFactory jedisConnectionFactory = (LettuceConnectionFactory) redisTemplate
				.getConnectionFactory();
		jedisConnectionFactory.setDatabase(dbIndex);
		redisTemplate.setConnectionFactory(jedisConnectionFactory);
	}

主要修改的了部分方法的参数,增加数据库选择。同事增加了选择数据库方法。

测试1

@RunWith(SpringRunner.class)
@SpringBootTest
public class XquantXcrmsApplicationTests {
	
	@Autowired
	private RedisUtils redisUtils;
	

	@Test
	public void contextLoads() {
		List list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 11);
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory().getConnection());
		List result = this.redisUtils.get("哈哈哈", List.class, 12);
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory().getConnection());
		System.out.println(result);
	}
}

分别为往11号库存一次,然后再从12号库去一次。
运行结果如下:

2018-10-18 18:50:36.203  INFO 11456 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@b01cb8d
org.springframework.data.redis.connection.lettuce.LettuceConnection@38c460e8
---------------------------------
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@b01cb8d
org.springframework.data.redis.connection.lettuce.LettuceConnection@4e67cfe1
null

修改测试代码如下

@RunWith(SpringRunner.class)
@SpringBootTest
public class XquantXcrmsApplicationTests {
	
	@Autowired
	private RedisUtils redisUtils;
	

	@Test
	public void contextLoads() {
		List list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 12);
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory());
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory().getConnection());
		System.out.println("---------------------------------");
		List result = this.redisUtils.get("哈哈哈", List.class, 11);
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory());
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory().getConnection());
		System.out.println(result);
	}
}

结果

2018-10-18 18:53:02.036  INFO 12524 --- [           main] io.lettuce.core.KqueueProvider           : Starting without optional kqueue library
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@685d7ba5
org.springframework.data.redis.connection.lettuce.LettuceConnection@16d41725
---------------------------------
org.springframework.data.redis.connection.lettuce.LettuceConnectionFactory@685d7ba5
org.springframework.data.redis.connection.lettuce.LettuceConnection@4df7d9ee
[2333, test1]

观察redis客户端
Springboot整合redis切库问题_第3张图片
Springboot整合redis切库问题_第4张图片
测试没有问题

方案二,用Jedis来实现

实际上用原生的Jedis也是可以实现切库的。
yml文件配置:

spring:
  redis:
    host: localhost
    port: 6379
    password: 
    timeout: 6000ms
    jedis:
      pool:
        max-active: 1000  # 连接池最大连接数(使用负值表示没有限制)
        max-wait: -1ms      # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-idle: 10      # 连接池中的最大空闲连接
        min-idle: 5       # 连接池中的最小空闲连接

Jedis配置类

/**
 * @author chunhui.tan
 * @version 创建时间:2018年10月18日 下午1:42:59
 *
 */
@Configuration
public class JedisConfiguration {
	
	/**
	 * 注入spirng中的读取redis配置的类
	 */
	@Autowired
	private RedisProperties properties;

	@Bean
	public JedisPool getJedisPool() {
		JedisPoolConfig config = new JedisPoolConfig();
		config.setMaxIdle(properties.getJedis().getPool().getMaxIdle());
		config.setMaxTotal(properties.getJedis().getPool().getMaxActive());
		config.setMaxWaitMillis(properties.getJedis().getPool().getMaxWait().toMillis());
		JedisPool pool = new JedisPool(config, properties.getHost(), properties.getPort(),
				Integer.valueOf(Long.toString(properties.getTimeout().getSeconds())));
		return pool;
	}

}

Jedis工具类

/**
 * @author chunhui.tan
 * @version 创建时间:2018年10月18日 下午2:31:35
 *
 */
@Component
public class RedisUtils {

	@Autowired
	private JedisPool jedisPool;

	/** 不设置过期时长 */
	public final static int NOT_EXPIRE = -1;

	private final static Gson gson = new Gson();

	/**
	 * 插入值-对象,指定数据库 指定过期时间
	 * 
	 * @param key     键
	 * @param value   值
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 */
	public void set(String key, Object value, Integer dbIndex, int expire) {
		Jedis jedis = getJedis(dbIndex);
		jedis.set(key, toJson(value));
		if (expire != NOT_EXPIRE) {
			jedis.expire(key, expire);
		}
	}

	/**
	 * 插入值-对象,指定数据库索引
	 * 
	 * @param key     键
	 * @param value   值
	 * @param dbIndex 数据库索引 范围 0-15,默认0
	 */
	public void set(String key, Object value, Integer dbIndex) {
		set(key, value, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 插入值-对象 ,默认0 index数据库
	 * 
	 * @param key   键
	 * @param value 值
	 */
	public void set(String key, Object value) {
		set(key, value, 0, NOT_EXPIRE);
	}

	/**
	 * 获取值-对象,指定数据库索引,并设置过期时间
	 * 
	 * @param key     键
	 * @param clazz   字节码对象
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 * @return
	 */
	public  T get(String key, Class clazz, Integer dbIndex, int expire) {
		Jedis jedis = getJedis(dbIndex);
		try {
			String value = jedis.get(key);
			if (expire != NOT_EXPIRE) {
				jedis.expire(key, expire);
			}
			return value == null ? null : fromJson(value, clazz);
		} finally {
			jedis.close();
		}
	}

	/**
	 * 取值-对象 指定数据库索引
	 * 
	 * @param key     键
	 * @param clazz   字节码对象
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @return
	 */
	public  T get(String key, Class clazz, Integer dbIndex) {
		return get(key, clazz, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-对象
	 * 
	 * @param key   键
	 * @param clazz 字节码对象
	 * @return
	 */
	public  T get(String key, Class clazz) {
		return get(key, clazz, 0, NOT_EXPIRE);
	}

	/**
	 * 取值-字符串,指定数据库索引,设置过期时间
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 * @return
	 */
	public String get(String key, Integer dbIndex, int expire) {
		Jedis jedis = getJedis(dbIndex);
		try {
			String value = jedis.get(key);
			if (expire != NOT_EXPIRE) {
				jedis.expire(key, expire);
			}
			return value;
		} finally {
			jedis.close();
		}
	}

	/**
	 * 取值-字符串,指定数据库索引
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @return
	 */
	public String get(String key, Integer dbIndex) {
		return get(key, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-字符串
	 * 
	 * @param key 键
	 * @return
	 */
	public String get(String key) {
		return get(key, 0, NOT_EXPIRE);
	}

	/**
	 * 删除 指定数据库索引
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 */
	public void delete(String key, Integer dbIndex) {
		Jedis jedis = getJedis(dbIndex);
		try {
			jedis.del(key);
		} finally {
			jedis.close();
		}
	}

	/**
	 * 删除
	 * 
	 * @param key 键
	 */
	public void delete(String key) {
		delete(key, 0);
	}

	/**
	 * 设置过期时间
	 * 
	 * @param key     键
	 * @param dbIndex 数据库索引 范围 0-15 默认0
	 * @param expire  过期时间 单位:秒
	 */
	public void expire(String key, Integer dbIndex, int expire) {
		Jedis jedis = getJedis(dbIndex);
		try {
			if (expire != NOT_EXPIRE) {
				jedis.expire(key, expire);
			}
		} finally {
			jedis.close();
		}
	}

	/**
	 * 设置过期时间
	 * 
	 * @param key    键
	 * @param expire 过期时间 单位:秒
	 */
	public void expire(String key, int expire) {
		expire(key, 0, expire);
	}

	/**
	 * 获取jedis对象,并指定dbIndex
	 * 
	 * @param dbIndex
	 */
	private Jedis getJedis(Integer dbIndex) {
		Jedis jedis = jedisPool.getResource();
		if (dbIndex == null || dbIndex > 15 || dbIndex < 0) {
			dbIndex = 0;
		}
		jedis.select(dbIndex);
		return jedis;
	}

	/**
	 * Object转成JSON数据
	 */
	private String toJson(Object object) {
		if (object instanceof Integer || object instanceof Long || object instanceof Float || object instanceof Double
				|| object instanceof Boolean || object instanceof String) {
			return String.valueOf(object);
		}
		return gson.toJson(object);

	}

	/**
	 * JSON数据,转成Object
	 */
	private  T fromJson(String json, Class clazz) {
		return gson.fromJson(json, clazz);
	}

里面的核心方法:

/**
	 * 获取jedis对象,并指定dbIndex
	 * 
	 * @param dbIndex
	 */
	private Jedis getJedis(Integer dbIndex) {
		Jedis jedis = jedisPool.getResource();
		if (dbIndex == null || dbIndex > 15 || dbIndex < 0) {
			dbIndex = 0;
		}
		jedis.select(dbIndex);
		return jedis;
	}

即在通过注入的JedisPool获取Jedis对象时,指定一下数据库即可

测试2

情况redis,然后执行以下代码

@RunWith(SpringRunner.class)
@SpringBootTest
public class XquantTestApplicationTests {
	
	@Autowired
	private RedisUtils redisUtils;
	
	@Test
	public void contextLoads() {
		List list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 12);
		
		System.out.println("---------------------------------");
		List result = this.redisUtils.get("哈哈哈", List.class, 11);
		
		System.out.println(result);
	}

}

控制台

---------------------------------
null

观察redis数据库:
Springboot整合redis切库问题_第5张图片
然后再执行以下代码:

@RunWith(SpringRunner.class)
@SpringBootTest
public class XquantTestApplicationTests {
	
	@Autowired
	private RedisUtils redisUtils;
	
	@Test
	public void contextLoads() {
		List list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 11);
		
		System.out.println("---------------------------------");
		List result = this.redisUtils.get("哈哈哈", List.class, 12);
		
		System.out.println(result);
	}

}

控制台

---------------------------------
[2333, test1]

观察redis数据库
Springboot整合redis切库问题_第6张图片
测试没有问题

总结

可能redis切库在日常业务中用到的地方不多,但是我碰巧遇到了这样的需求,而且在和同事一起研究了一下,他研究RedisTemplate,我研究Jedis,最后发现两种方法都可以实现,故在此记录一下。至于其中的性能差别,或者链接健康情况,还没来得及测试和讨论。

來源:https://blog.csdn.net/qq_38846242/article/details/83151489

你可能感兴趣的:(springboot)