spring boot專案中使用 RedisTemplate/StringRedisTemplate 學習經歷
專案開發時遇到需要去防止兩個服務同時跑一個功能時而導致公用的一個表出現資料錯誤的問題,領導說了幾個解決方案redis是唯一一個聽過的就趕緊學了一下,因為並未去很好的瀏覽專案結構剛開始繞了很大一圈,自己建立連線池配置檔案引pom啥的,結果發現都是已經搭好的,但也對redis有了更深的認識,先貼下程式碼
application的配置
#Jedis版本 #redis.server.host=66666666.666.66.66 #redis.server.port=6666 #redis.server.password= #redis.server.timeOut=3000 #redis.server.maxIdle=50 #redis.server.maxWaitMillis=5000 #redis.server.maxTotal=500
pom.xml
<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.9.0</version> </dependency>
連線的屬性
import org.springframework.boot.context.properties.ConfigurationProperties;/** * ClassName JedisProperties * Description TODO * * @Author * @Version **/ @ConfigurationProperties(prefix = JedisProperties.JEDIS_PREFIX) public class JedisProperties { public static final String JEDIS_PREFIX = "redis.server"; private String host; private int port; privateString password; private int maxTotal; private int maxIdle; private int maxWaitMillis; private int timeOut; public int getTimeOut() { return timeOut; } public void setTimeOut(int timeOut) { this.timeOut = timeOut; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public int getMaxTotal() { return maxTotal; } public void setMaxTotal(int maxTotal) { this.maxTotal = maxTotal; } public int getMaxIdle() { return maxIdle; } public void setMaxIdle(int maxIdle) { this.maxIdle = maxIdle; } public int getMaxWaitMillis() { return maxWaitMillis; } public void setMaxWaitMillis(int maxWaitMillis) { this.maxWaitMillis = maxWaitMillis; } }
建立連線池Bean
import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.boot.autoconfigure.condition.ConditionalOnClass; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import redis.clients.jedis.JedisPool; import redis.clients.jedis.JedisPoolConfig; /** * ClassName JedisConfig * Description TODO * * @Author * @Version **/ @Configuration @EnableConfigurationProperties(JedisProperties.class) @ConditionalOnClass(JedisClientSingle.class) public class JedisConfig { private Logger logger = LoggerFactory.getLogger(JedisConfig.class); @Autowired private JedisProperties prop; @Bean(name = "jedisPool") public JedisPool jedisPool() { JedisPoolConfig config = new JedisPoolConfig(); config.setMaxTotal(prop.getMaxTotal()); config.setMaxIdle(prop.getMaxIdle()); config.setMaxWaitMillis(prop.getMaxWaitMillis()); return new JedisPool(config, prop.getHost(), prop.getPort(), prop.getTimeOut(), prop.getPassword()); } @Bean @ConditionalOnMissingBean(JedisClientSingle.class) public JedisClientSingle redisClient(@Qualifier("jedisPool") JedisPool pool) { logger.info("噹噹噹當~~~~~Redis Client==Host={},Port={}", prop.getHost(), prop.getPort()); JedisClientSingle redisClient = new JedisClientSingle(); redisClient.setJedisPool(pool); return redisClient; } }
連線pool的操作類(這地方借鑑了很多帖子的方法,揉到一起了)
import redis.clients.jedis.Jedis; import redis.clients.jedis.JedisPool; import java.util.List; /** * ClassName JedisClientSingle * Description TODO * * @Author * @Version **/ public class JedisClientSingle { private JedisPool jedisPool; public String get(String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.get(key); jedis.close(); return string; } public String set(String key, String value) { Jedis jedis = jedisPool.getResource(); String string = jedis.set(key, value); jedis.close(); return string; } public String hget(String hkey, String key) { Jedis jedis = jedisPool.getResource(); String string = jedis.hget(hkey, key); jedis.close(); return string; } public long hset(String hkey, String key, String value) { Jedis jedis = jedisPool.getResource(); Long result = jedis.hset(hkey, key, value); jedis.close(); return result; } public long incr(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.incr(key); jedis.close(); return result; } public long expire(String key, int second) { Jedis jedis = jedisPool.getResource(); Long result = jedis.expire(key, second); jedis.close(); return result; } public long ttl(String key) { Jedis jedis = jedisPool.getResource(); Long result = jedis.ttl(key); jedis.close(); return result; } public void deleteByKey(String key){ Jedis jedis = jedisPool.getResource(); jedis.del(key); jedis.close(); } /**SerializeUtil.serializeList(list) * 設定List集合 * @param key * @param list */ public void setList(String key ,List<?> list){ Jedis jedis = jedisPool.getResource(); try { if(list == null || list.size() == 0){ jedis.set(key.getBytes(), "".getBytes()); }else{//如果list為空,則設定一個空 jedis.set(key.getBytes(), SerializeUtil.serialize(list)); } } catch (Exception e) { e.printStackTrace(); } finally { jedis.close(); } } /** * 獲取List集合 * @param key * @return */ public List<?> getList(String key){ Jedis jedis = jedisPool.getResource(); if(jedis == null || !jedis.exists(key)){ return null; } byte[] data = jedis.get(key.getBytes()); jedis.close(); return SerializeUtil.unserializeForList(data); } public JedisPool getJedisPool() { return jedisPool; } public void setJedisPool(JedisPool jedisPool) { this.jedisPool = jedisPool; } }
工具類(借鑑自其他帖子)
import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; /** * ClassName SerializeUtil * Description redis工具類 序列化物件工具類,用於儲存和讀取redis資料使用 * * @Author * @Version **/ public class SerializeUtil { private static Logger log = LoggerFactory.getLogger(SerializeUtil.class); /** * 序列化物件 * @param object * @return */ public static byte[] serialize(Object object) { ObjectOutputStream oos = null; ByteArrayOutputStream baos = null; byte[] bytes = null; try { // 序列化 baos = new ByteArrayOutputStream(); oos = new ObjectOutputStream(baos); oos.writeObject(object); bytes = baos.toByteArray(); } catch (Exception e) { e.printStackTrace(); } finally { try { if (oos != null) { oos.close(); } if (baos != null) { baos.close(); } } catch (Exception e2) { e2.printStackTrace(); } } return bytes; } /** * 反序列化物件 * @param bytes * @return */ public static Object unserialize(byte[] bytes) { Object obj = null; ByteArrayInputStream bais = null; try { // 反序列化 bais = new ByteArrayInputStream(bytes); ObjectInputStream ois = new ObjectInputStream(bais); obj = ois.readObject(); ois.close(); bais.close(); } catch (Exception e) { e.printStackTrace(); } return obj; } /** * 關閉的資料來源或目標。呼叫 close()方法可釋放物件儲存的資源(如開啟檔案) * 關閉此流並釋放與此流關聯的所有系統資源。如果已經關閉該流,則呼叫此方法無效。 * @param closeable */ public static void close(Closeable closeable) { if (closeable != null) { try { closeable.close(); } catch (Exception e) { log.info("Unable to close %s", closeable, e); } } } /** * 列表序列化(用於Redis整存整取) * @param value * @return */ public static <T> byte[] serialize(List<T> value) { if (value == null) { throw new NullPointerException("Can't serialize null"); } byte[] rv=null; ByteArrayOutputStream bos = null; ObjectOutputStream os = null; try { bos = new ByteArrayOutputStream(); os = new ObjectOutputStream(bos); for(T obj : value){ os.writeObject(obj); } os.writeObject(null); os.close(); bos.close(); rv = bos.toByteArray(); } catch (IOException e) { throw new IllegalArgumentException("Non-serializable object", e); } finally { close(os); close(bos); } return rv; } /** * 反序列化列表(用於Redis整存整取) * @param in * @return */ public static <T> List<T> unserializeForList(byte[] in) { List<T> list = new ArrayList<T>(); ByteArrayInputStream bis = null; ObjectInputStream is = null; try { if(in != null) { bis=new ByteArrayInputStream(in); is=new ObjectInputStream(bis); while (true) { T obj = (T) is.readObject(); if(obj == null){ break; }else{ list.add(obj); } } is.close(); bis.close(); } } catch (IOException e) { log.warn("Caught IOException decoding %d bytes of data", in == null ? 0 : in.length, e); } catch (ClassNotFoundException e) { log.warn("Caught CNFE decoding %d bytes of data", in == null ? 0 : in.length, e); } finally { close(is); close(bis); } return list; } }
在需要使用的類中注入或者建立類,有的地方注入會報錯,需要給類新增@Component // @Autowired // private JedisClientSingle jedisClient; // // private JedisShardInfo jedisShardInfo; //Jedis版本 // if (CollectionUtils.isNotEmpty(list)) { // //放到redis,將查詢的accountList // jedisClient.setList("getAccountList", list); // //設定過期(單位:秒) // jedisClient.expire("getAccountList",600); // } // redisTemplate.setConnectionFactory((RedisConnectionFactory) jedisClient.getJedisPool()); // //刪除key // jedisClient.deleteByKey("getAccountList"); // //取redis // List<Map> listAccount = (List<Map>) jedisClient.getList("getAccountList");
刪除key是測試時自用的,現在Jedis版本的是好用了,然後百度時發現現在已經是springboot2.0版本了,reids的使用和api也有更好的選擇,我就全域性搜了一下專案中竟然有,然後就開始了把這個版本的改成RedisTemplate版本的,這個是通過pom。xml引的一些架包,貌似是對Jedis進行了進一步的封裝,不用在配置連線池它會自動去建立,只需要把連線池的一些屬性配置好即可,和這個Jedis的一比簡直是方便很多,貼下程式碼。
#Redis配置 spring.redis.database=0 spring.redis.host=666.6666.666 spring.redis.port=66666 spring.redis.timeout=3000 spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0
pom.xml(看著比較像的,因為是專案自帶的可能會有遺漏建議你們再百度一下)
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> <version>1.5.13.RELEASE</version> </dependency>
應用
if (CollectionUtils.isNotEmpty(list)) { //放到redis,將查詢的accountList(不分庫) redisTemplate.opsForList().leftPush("getAccountList",list); //設定過期(單位:分鐘) redisTemplate.expire("getAccountList",5, TimeUnit.MINUTES); } //取redis List<Map> listAccount = (List<Map>) redisTemplate.opsForList().leftPop("getAccountList");
if (stringRedisTemplate.hasKey(getAccountList)) {
}
這個redisTemplate裡封裝了對redis各個型別的方法,然後我是隻用了list,這個list有left和right的區別是遍歷時的區別,反正其他帖子的樓主是建議若是leftPush存的,就從leftPop去,儘量不要left和right混合使用。若是需要判斷key是否為空就可以用下面的那個String的,是對redisTemplate的一個封裝類,借鑑中的帖子解釋的更好這裡就不贅述了,下面貼上借鑑的帖子,謝謝這些樓主。
https://blog.csdn.net/u010473656/article/details/78838254
https://blog.csdn.net/bcqtt/article/details/72286359
https://www.cnblogs.com/superfj/p/9232482.html
https://blog.csdn.net/lichuangcsdn/article/details/80866182
//--redisTemplate對比stringRedisTemplate
https://blog.csdn.net/Abysscarry/article/details/80557347