概述
本文內容主要
-
關于spring-redis
-
關于redis的key設計
-
redis的基本資料結構
-
介紹redis與springboot的整合
-
sringboot中的redistemplate的使用
關于spring-redis
spring-data-redis針對jedis提供了如下功能:
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,
關于key的設計
key的存活時間:
無論什么時候,只要有可能就利用key超時的優勢,一個很好的例子就是儲存一些諸如臨時認證key之類的東西,當你去查找一個授權key時——以OAUTH為例——通常會得到一個超時時間,
這樣在設定key的時候,設成同樣的超時時間,Redis就會自動為你清除,
關系型資料庫的redis
1: 把表名轉換為key前綴 如, tag:
2: 第2段放置用于區磁區key的欄位--對應mysql中的主鍵的列名,如userid
3: 第3段放置主鍵值,如2,3,4…., a , b ,c
4: 第4段,寫要存盤的列名
例:user:userid:9:username
Redis的資料型別
String字串
-
string是redis最基本的型別,一個key對應一個value,
-
string型別是二進制安全的,意思是redis的string可以包含任何資料,比如jpg圖片或者序列化的物件 ,
-
string型別是Redis最基本的資料型別,一個鍵最大能存盤512MB,
String型別的操作參考:
http://www.runoob.com/redis/redis-strings.html
鏈表
-
redis串列是簡單的字串串列,排序為插入的順序,串列的最大長度為2^32-1,
-
redis的串列是使用鏈表實作的,這意味著,即使串列中有上百萬個元素,增加一個元素到串列的頭部或尾部的操作都是在常量的時間完成,
-
可以用串列獲取最新的內容(像帖子,微博等),用ltrim很容易就會獲取最新的內容,并移除舊的內容,
-
用串列可以實作生產者消費者模式,生產者呼叫lpush添加項到串列中,消費者呼叫rpop從串列中提取,如果沒有元素,則輪詢去獲取,或者使用brpop等待生產者添加項到串列中,
List型別的操作參考:
http://www.runoob.com/redis/redis-lists.html
集合
-
redis集合是無序的字串集合,集合中的值是唯一的,無序的,可以對集合執行很多操作,例如,測驗元素是否存在,對多個集合執行交集、并集和差集等等,
-
我們通常可以用集合存盤一些無關順序的,表達物件間關系的資料,例如用戶的角色,可以用sismember很容易就判斷用戶是否擁有某個角色,
-
在一些用到隨機值的場合是非常適合的,可以用 srandmember/spop 獲取/彈出一個隨機元素,同時,使用@EnableCaching開啟宣告式快取支持,這樣就可以使用基于注解的快取技術,注解快取是一個對快取使用的抽象,通過在代碼中添加下面的一些注解,達到快取的效果,
Set型別的操作參考:
http://www.runoob.com/redis/redis-sets.html
ZSet 有序集合
-
有序集合由唯一的,不重復的字串元素組成,有序集合中的每個元素都關聯了一個浮點值,稱為分數,可以把有序看成hash和集合的混合體,分數即為hash的key,
-
有序集合中的元素是按序存盤的,不是請求時才排序的,
ZSet型別的操作型別
http://www.runoob.com/redis/redis-sorted-sets.html
Hash-哈希
-
redis的哈希值是字串欄位和字串之間的映射,是表示物件的完美資料型別,
-
哈希中的欄位數量沒有限制,所以可以在你的應用程式以不同的方式來使用哈希,
Hash型別的操作參考:
http://www.runoob.com/redis/redis-hashes.html
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:洗掉快取中的資料,
本文代碼
https://github.com/JayTange/springbootRedis.git
參考
https://www.cnblogs.com/chiangchou/p/7748009.html
http://www.cnblogs.com/chiangchou/p/redis-1.html
寫在最后
分享一些Java學習資料獲取方式:點擊鏈接《Java面試BAT通關手冊》,覆寫了Java核心技術、JVM、Java并發、SSM、微服務、資料庫、資料結構等等,
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/96337.html
標籤:Java
下一篇:Java演算法題——牛牛消消樂
