概述
本文內容主要html
- 關於spring-redis
- 關於redis的key設計
- redis的基本數據結構
- 介紹redis與springboot的整合
- sringboot中的redistemplate的使用
以前看了不少博客,大都都只是粗略的介紹,這裏想要記錄的全面一些,也算是一個學習的過程 首發於個人我的博客:janti的我的博客java
關於spring-redis
spring-data-redis針對jedis提供了以下功能:mysql
1. 鏈接池自動管理,提供了一個高度封裝的「RedisTemplate」類 2. 針對jedis客戶端中大量api進行了歸類封裝,將同一類型操做封裝爲operation接口 ValueOperations:簡單K-V操做 SetOperations:set類型數據操做 ZSetOperations:zset類型數據操做 HashOperations:針對map類型的數據操做 ListOperations:針對list類型的數據操做 3. 提供了對key的「bound」(綁定)便捷化操做API,能夠經過bound封裝指定的key,而後進行一系列的操做而無須「顯式」的再次指定Key,即BoundKeyOperations: BoundValueOperations BoundSetOperations BoundListOperations BoundSetOperations BoundHashOperations 4. 將事務操做封裝,有容器控制。 5. 針對數據的「序列化/反序列化」,提供了多種可選擇策略(RedisSerializer) JdkSerializationRedisSerializer:POJO對象的存取場景,使用JDK自己序列化機制,將pojo類經過ObjectInputStream/ObjectOutputStream進行序列化操做,最終redis-server中將存儲字節序列。是目前最經常使用的序列化策略。 StringRedisSerializer:Key或者value爲字符串的場景,根據指定的charset對數據的字節序列編碼成string,是「new String(bytes, charset)」和「string.getBytes(charset)」的直接封裝。是最輕量級和高效的策略。 JacksonJsonRedisSerializer:jackson-json工具提供了javabean與json之間的轉換能力,能夠將pojo實例序列化成json格式存儲在redis中,也能夠將json格式的數據轉換成pojo實例。由於jackson工具在序列化和反序列化時,須要明確指定Class類型,所以此策略封裝起來稍微複雜。【須要jackson-mapper-asl工具支持】 OxmSerializer:提供了將javabean與xml之間的轉換能力,目前可用的三方支持包括jaxb,apache-xmlbeans;redis存儲的數據將是xml工具。不過使用此策略,編程將會有些難度,並且效率最低;不建議使用。【須要spring-oxm模塊的支持】
若是你的數據須要被第三方工具解析,那麼數據應該使用StringRedisSerializer而不是JdkSerializationRedisSerializer。git
關於key的設計
key的存活時間:
不管何時,只要有可能就利用key超時的優點。一個很好的例子就是儲存一些諸如臨時認證key之類的東西。當你去查找一個受權key時——以OAUTH爲例——一般會獲得一個超時時間。 這樣在設置key的時候,設成一樣的超時時間,Redis就會自動爲你清除。github
關係型數據庫的redis
1: 把表名轉換爲key前綴 如, tag: 2: 第2段放置用於區分區key的字段--對應mysql中的主鍵的列名,如userid 3: 第3段放置主鍵值,如2,3,4...., a , b ,c 4: 第4段,寫要存儲的列名 例:user:userid:9:usernameweb
Redis的數據類型
String字符串
- string是redis最基本的類型,一個key對應一個value。
- string類型是二進制安全的。意思是redis的string能夠包含任何數據。好比jpg圖片或者序列化的對象 。
- string類型是Redis最基本的數據類型,一個鍵最大能存儲512MB。
- String類型的操做參考
鏈表
-
redis列表是簡單的字符串列表,排序爲插入的順序。列表的最大長度爲2^32-1。redis
-
redis的列表是使用鏈表實現的,這意味着,即便列表中有上百萬個元素,增長一個元素到列表的頭部或尾部的操做都是在常量的時間完成。spring
-
能夠用列表獲取最新的內容(像帖子,微博等),用ltrim很容易就會獲取最新的內容,並移除舊的內容。sql
-
用列表能夠實現生產者消費者模式,生產者調用lpush添加項到列表中,消費者調用rpop從列表中提取,若是沒有元素,則輪詢去獲取,或者使用brpop等待生產者添加項到列表中。數據庫
集合
- redis集合是無序的字符串集合,集合中的值是惟一的,無序的。能夠對集合執行不少操做,例如,測試元素是否存在,對多個集合執行交集、並集和差集等等。
- 咱們一般能夠用集合存儲一些無關順序的,表達對象間關係的數據,例如用戶的角色,能夠用sismember很容易就判斷用戶是否擁有某個角色。
- 在一些用到隨機值的場合是很是適合的,能夠用 srandmember/spop 獲取/彈出一個隨機元素。 同時,使用@EnableCaching開啓聲明式緩存支持,這樣就可使用基於註解的緩存技術。註解緩存是一個對緩存使用的抽象,經過在代碼中添加下面的一些註解,達到緩存的效果。
- Set類型的操做參考
ZSet 有序集合
-
有序集合由惟一的,不重複的字符串元素組成。有序集合中的每一個元素都關聯了一個浮點值,稱爲分數。能夠把有序當作hash和集合的混合體,分數即爲hash的key。
-
有序集合中的元素是按序存儲的,不是請求時才排序的。
Hash-哈希
-
redis的哈希值是字符串字段和字符串之間的映射,是表示對象的完美數據類型。
-
哈希中的字段數量沒有限制,因此能夠在你的應用程序以不一樣的方式來使用哈希。
springboot 與redis的整合
pom文件
依賴以下:
<parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>1.5.1.RELEASE</version> <relativePath/> </parent> <dependencies> <!-- spring boot 配置 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> </dependencies>
application.properties
# Redis數據庫索引(默認爲0) spring.redis.database=0 # Redis服務器地址 spring.redis.host=127.0.0.1 # Redis服務器鏈接端口 spring.redis.port=6379 # Redis服務器鏈接密碼(默認爲空) spring.redis.password= # 鏈接池最大鏈接數(使用負值表示沒有限制) spring.redis.pool.max-active=8 # 鏈接池最大阻塞等待時間(使用負值表示沒有限制) spring.redis.pool.max-wait=-1 # 鏈接池中的最大空閒鏈接 spring.redis.pool.max-idle=8 # 鏈接池中的最小空閒鏈接 spring.redis.pool.min-idle=0 # 鏈接超時時間(毫秒) spring.redis.timeout=0
redisTemplate的配置
新建一個redisConfig類,進行相關bean的配置:
package com.config; import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.databind.ObjectMapper; import org.springframework.cache.CacheManager; 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.data.redis.cache.RedisCacheManager; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.core.*; import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; /** * @author janti * reids 相關bean的配置 */ @Configuration @EnableCaching public class RedisConfig extends CachingConfigurerSupport { /** * 選擇redis做爲默認緩存工具 * @param redisTemplate * @return */ @Bean public CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); return rcm; } /** * retemplate相關配置 * @param factory * @return */ @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); // 配置鏈接工廠 template.setConnectionFactory(factory); //使用Jackson2JsonRedisSerializer來序列化和反序列化redis的value值(默認使用JDK的序列化方式) Jackson2JsonRedisSerializer jacksonSeial = new Jackson2JsonRedisSerializer(Object.class); ObjectMapper om = new ObjectMapper(); // 指定要序列化的域,field,get和set,以及修飾符範圍,ANY是都有包括private和public om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); // 指定序列化輸入的類型,類必須是非final修飾的,final修飾的類,好比String,Integer等會跑出異常 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); jacksonSeial.setObjectMapper(om); // 值採用json序列化 template.setValueSerializer(jacksonSeial); //使用StringRedisSerializer來序列化和反序列化redis的key值 template.setKeySerializer(new StringRedisSerializer()); // 設置hash key 和value序列化模式 template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(jacksonSeial); template.afterPropertiesSet(); return template; } /** * 對hash類型的數據操做 * * @param redisTemplate * @return */ @Bean public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForHash(); } /** * 對redis字符串類型數據操做 * * @param redisTemplate * @return */ @Bean public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForValue(); } /** * 對鏈表類型的數據操做 * * @param redisTemplate * @return */ @Bean public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForList(); } /** * 對無序集合類型的數據操做 * * @param redisTemplate * @return */ @Bean public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForSet(); } /** * 對有序集合類型的數據操做 * * @param redisTemplate * @return */ @Bean public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) { return redisTemplate.opsForZSet(); } }
-
spring-redis中使用了RedisTemplate來進行redis的操做,經過泛型的K和V設置鍵值對的對象類型。這裏使用了string做爲key的對象類型,值爲Object。
-
對於Object,spring-redis默認使用了jdk自帶的序列化,不推薦使用默認了。因此使用了json的序列化方式
-
對spring-redis對redis的五種數據類型也有支持
-
HashOperations:對hash類型的數據操做
-
ValueOperations:對redis字符串類型數據操做
-
ListOperations:對鏈表類型的數據操做
-
SetOperations:對無序集合類型的數據操做
-
ZSetOperations:對有序集合類型的數據操做
redis操做的工具類
package com.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.data.redis.core.RedisTemplate; import org.springframework.stereotype.Component; import java.util.Collection; import java.util.Date; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.stream.Collectors; import java.util.stream.Stream; @Component public class RedisService { @Autowired private RedisTemplate<String, String> redisTemplate; /** * 默認過時時長,單位:秒 */ public static final long DEFAULT_EXPIRE = 60 * 60 * 24; /** * 不設置過時時長 */ public static final long NOT_EXPIRE = -1; public boolean existsKey(String key) { return redisTemplate.hasKey(key); } /** * 重名名key,若是newKey已經存在,則newKey的原值被覆蓋 * * @param oldKey * @param newKey */ public void renameKey(String oldKey, String newKey) { redisTemplate.rename(oldKey, newKey); } /** * newKey不存在時才重命名 * * @param oldKey * @param newKey * @return 修改爲功返回true */ public boolean renameKeyNotExist(String oldKey, String newKey) { return redisTemplate.renameIfAbsent(oldKey, newKey); } /** * 刪除key * * @param key */ public void deleteKey(String key) { redisTemplate.delete(key); } /** * 刪除多個key * * @param keys */ public void deleteKey(String... keys) { Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet()); redisTemplate.delete(kSet); } /** * 刪除Key的集合 * * @param keys */ public void deleteKey(Collection<String> keys) { Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet()); redisTemplate.delete(kSet); } /** * 設置key的生命週期 * * @param key * @param time * @param timeUnit */ public void expireKey(String key, long time, TimeUnit timeUnit) { redisTemplate.expire(key, time, timeUnit); } /** * 指定key在指定的日期過時 * * @param key * @param date */ public void expireKeyAt(String key, Date date) { redisTemplate.expireAt(key, date); } /** * 查詢key的生命週期 * * @param key * @param timeUnit * @return */ public long getKeyExpire(String key, TimeUnit timeUnit) { return redisTemplate.getExpire(key, timeUnit); } /** * 將key設置爲永久有效 * * @param key */ public void persistKey(String key) { redisTemplate.persist(key); } }
redis的key工具類
package com.util; /** * redisKey設計 */ public class RedisKeyUtil { /** * redis的key * 形式爲: * 表名:主鍵名:主鍵值:列名 * * @param tableName 表名 * @param majorKey 主鍵名 * @param majorKeyValue 主鍵值 * @param column 列名 * @return */ public static String getKeyWithColumn(String tableName,String majorKey,String majorKeyValue,String column){ StringBuffer buffer = new StringBuffer(); buffer.append(tableName).append(":"); buffer.append(majorKey).append(":"); buffer.append(majorKeyValue).append(":"); buffer.append(column); return buffer.toString(); } /** * redis的key * 形式爲: * 表名:主鍵名:主鍵值 * * @param tableName 表名 * @param majorKey 主鍵名 * @param majorKeyValue 主鍵值 * @return */ public static String getKey(String tableName,String majorKey,String majorKeyValue){ StringBuffer buffer = new StringBuffer(); buffer.append(tableName).append(":"); buffer.append(majorKey).append(":"); buffer.append(majorKeyValue).append(":"); return buffer.toString(); } }
如何使用?
測試代碼
新建一個實體類:
package com.domain; public class UserVo { public static final String Table = "t_user"; private String name; private String address; private Integer age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public Integer getAge() { return age; } public void setAge(Integer age) { this.age = age; } @Override public String toString() { return "UserVo{" + "name='" + name + '\'' + ", address='" + address + '\'' + ", age=" + age + '}'; } }
再新建一個測試類:
package com.config; import com.domain.UserVo; import com.service.RedisService; import com.util.RedisKeyUtil; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.data.redis.core.*; import org.springframework.test.context.junit4.SpringRunner; import javax.annotation.Resource; import java.util.Set; import java.util.concurrent.TimeUnit; import static org.junit.Assert.*; @RunWith(SpringRunner.class) @SpringBootTest public class RedisConfigTest { @Autowired private StringRedisTemplate stringRedisTemplate; @Autowired private RedisTemplate redisTemplate; @Resource private ValueOperations<String,Object> 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; @Resource private RedisService redisService; @Test public void testObj() throws Exception{ UserVo userVo = new UserVo(); userVo.setAddress("上海"); userVo.setName("測試dfas"); userVo.setAge(123); ValueOperations<String,Object> operations = redisTemplate.opsForValue(); redisService.expireKey("name",20, TimeUnit.SECONDS); String key = RedisKeyUtil.getKey(UserVo.Table,"name",userVo.getName()); UserVo vo = (UserVo) operations.get(key); System.out.println(vo); } @Test public void testValueOption( )throws Exception{ UserVo userVo = new UserVo(); userVo.setAddress("上海"); userVo.setName("jantent"); userVo.setAge(23); valueOperations.set("test",userVo); System.out.println(valueOperations.get("test")); } @Test public void testSetOperation() throws Exception{ UserVo userVo = new UserVo(); userVo.setAddress("北京"); userVo.setName("jantent"); userVo.setAge(23); UserVo auserVo = new UserVo(); auserVo.setAddress("n櫃昂周"); auserVo.setName("antent"); auserVo.setAge(23); setOperations.add("user:test",userVo,auserVo); Set<Object> result = setOperations.members("user:test"); System.out.println(result); } @Test public void HashOperations() throws Exception{ UserVo userVo = new UserVo(); userVo.setAddress("北京"); userVo.setName("jantent"); userVo.setAge(23); hashOperations.put("hash:user",userVo.hashCode()+"",userVo); System.out.println(hashOperations.get("hash:user",userVo.hashCode()+"")); } @Test public void ListOperations() throws Exception{ UserVo userVo = new UserVo(); userVo.setAddress("北京"); userVo.setName("jantent"); userVo.setAge(23); // listOperations.leftPush("list:user",userVo); // System.out.println(listOperations.leftPop("list:user")); // pop以後 值會消失 System.out.println(listOperations.leftPop("list:user")); } }
註解緩存的使用
-
@Cacheable:在方法執行前Spring先查看緩存中是否有數據,若是有數據,則直接返回緩存數據;沒有則調用方法並將方法返回值放進緩存。
-
@CachePut:將方法的返回值放到緩存中。
-
@CacheEvict:刪除緩存中的數據。
最後全部的代碼都被上傳到個人github喜歡的話,給個start