1. 程式人生 > >Springboot整合redis切庫問題

Springboot整合redis切庫問題

切庫問題

由於工作業務需求,需要在單機redis中做切庫處理。一般來說,redis資料庫有16個數據庫,而且有對應的索引,分別為0-15,如下圖 在這裡插入圖片描述 目前的專案時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<String, Object> redisTemplate() {
        RedisTemplate<String, Object> 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<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForHash();
    }

    @Bean
    public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
        return redisTemplate.opsForValue();
    }

    @Bean
    public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForList();
    }

    @Bean
    public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForSet();
    }

    @Bean
    public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
        return redisTemplate.opsForZSet();
    }

RedisUtils

@Component
public class RedisUtils {
    @Autowired
    private RedisTemplate<String, Object> redisTemplate;
    @Resource(name="redisTemplate")
    private ValueOperations<String, String> valueOperations;
    @Resource(name="redisTemplate")
    private HashOperations<String, String, Object> hashOperations;
    @Resource(name="redisTemplate")
    private ListOperations<String, Object> listOperations;
    @Resource(name="redisTemplate")
    private SetOperations<String, Object> setOperations;
    @Resource(name="redisTemplate")
    private ZSetOperations<String, Object> 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> T get(String key, Class<T> 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> T get(String key, Class<T> 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> T fromJson(String json, Class<T> 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遇到的問題。 這裡面有提到遇到上面那個問題: 在這裡插入圖片描述 給出的解決方案是在例項化RedisTemplate時,不再注入RedisConnectionFactory,改為注入LettuceConnectionFactory ,並關閉共享連結。所以修改當前的redis配置和工具類: 修改後的Redis配置

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

	@Bean
	public RedisTemplate<String, Object> redisTemplate() {
		// 關閉共享連結
		factory.setShareNativeConnection(false);
		RedisTemplate<String, Object> 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<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForHash();
	}

	@Bean
	public ValueOperations<String, String> valueOperations(RedisTemplate<String, String> redisTemplate) {
		return redisTemplate.opsForValue();
	}

	@Bean
	public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForList();
	}

	@Bean
	public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForSet();
	}

	@Bean
	public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForZSet();
	}

主要修改了兩個地方,注入LettuceConnectionFactory ,關閉共享連結 修改後的RedisUtils

/**
 * Redis工具類
 * 
 * 封裝了物件和字串的存,取,刪除,設定過期時間操作. 所有操作可以指定資料庫索引. 存,取可以設定過期時間. 沒有設定預設過期時間,存值時儘量設定過期時間
 * 
 * @author chunhui.tan
 * @version 建立時間:2018年10月8日 下午3:31:00
 */
@Component
public class RedisUtils {
	@Autowired
	private RedisTemplate<String, Object> redisTemplate;
	@Autowired
	private ValueOperations<String, String> valueOperations;
	@Autowired
	private HashOperations<String, String, Object> hashOperations;
	@Autowired
	private ListOperations<String, Object> listOperations;
	@Autowired
	private SetOperations<String, Object> setOperations;
	@Autowired
	private ZSetOperations<String, Object> 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<String, Object> 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> T get(String key, Class<T> 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> T get(String key, Class<T> clazz, Integer dbIndex) {
		return get(key, clazz, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-物件
	 * 
	 * @param key   鍵
	 * @param clazz 位元組碼物件
	 * @return
	 */
	public <T> T get(String key, Class<T> 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> T fromJson(String json, Class<T> 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<String> list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 11);
		System.out.println(redisUtils.getRedisTemplate().getConnectionFactory().getConnection());
		List<String> 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.springf[email protected]b01cb8d
org.[email protected]38c460e8
---------------------------------
org.springf[email protected]b01cb8d
org.[email protected]4e67cfe1
null

修改測試程式碼如下

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

	@Test
	public void contextLoads() {
		List<String> 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<String> 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.springf[email protected]685d7ba5
org.[email protected]16d41725
---------------------------------
org.springf[email protected]685d7ba5
org.[email protected]4df7d9ee
[2333, test1]

觀察redis客戶端 在這裡插入圖片描述 在這裡插入圖片描述 測試沒有問題

方案二,用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> T get(String key, Class<T> 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> T get(String key, Class<T> clazz, Integer dbIndex) {
		return get(key, clazz, dbIndex, NOT_EXPIRE);
	}

	/**
	 * 取值-物件
	 * 
	 * @param key   鍵
	 * @param clazz 位元組碼物件
	 * @return
	 */
	public <T> T get(String key, Class<T> 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> T fromJson(String json, Class<T> 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<String> list = new ArrayList<>();
		list.add("2333");
		list.add("test1");
		this.redisUtils.set("哈哈哈", list, 12);
		
		System.out.println("---------------------------------");
		List<String> result = this.redisUtils.get("哈哈哈", List.class, 11);
		
		System.out.println(result);
	}

}

控制檯

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

觀察redis資料庫: 在這裡插入圖片描述 然後再執行以下程式碼:

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

}

控制檯

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

觀察redis資料庫 在這裡插入圖片描述 測試沒有問題

總結

可能redis切庫在日常業務中用到的地方不多,但是我碰巧遇到了這樣的需求,而且在和同事一起研究了一下,他研究RedisTemplate,我研究Jedis,最後發現兩種方法都可以實現,故在此記錄一下。至於其中的效能差別,或者連結健康情況,還沒來得及測試和討論。