概述
本文内容主要
- 关于spring-redis
- 关于redis的key设计
- redis的基本数据结构
- 介绍redis与springboot的整合
- sringboot中的redistemplate的使用
redis常用命令:redis常用命令
转载:janti的博客
关于spring-redis
spring-data-redis针对jedis提供了如下功能:
1. 连接池自动管理,提供了一个高度封装的“RedisTemplate”类
- 针对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
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类型的操作参考
链表
- redis列表是简单的字符串列表,排序为插入的顺序。列表的最大长度为2^32-1。
- redis的列表是使用链表实现的,这意味着,即使列表中有上百万个元素,增加一个元素到列表的头部或尾部的操作都是在常量的时间完成。
- 可以用列表获取最新的内容(像帖子,微博等),用ltrim很容易就会获取最新的内容,并移除旧的内容。
- 用列表可以实现生产者消费者模式,生产者调用lpush添加项到列表中,消费者调用rpop从列表中提取,如果没有元素,则轮询去获取,或者使用brpop等待生产者添加项到列表中。
- List类型的操作参考
集合
- redis集合是无序的字符串集合,集合中的值是唯一的,无序的。可以对集合执行很多操作,例如,测试元素是否存在,对多个集合执行交集、并集和差集等等。
- 我们通常可以用集合存储一些无关顺序的,表达对象间关系的数据,例如用户的角色,可以用sismember很容易就判断用户是否拥有某个角色。
- 在一些用到随机值的场合是非常适合的,可以用 srandmember/spop 获取/弹出一个随机元素。 同时,使用@EnableCaching开启声明式缓存支持,这样就可以使用基于注解的缓存技术。注解缓存是一个对缓存使用的抽象,通过在代码中添加下面的一些注解,达到缓存的效果。
- Set类型的操作参考
ZSet 有序集合
- 有序集合由唯一的,不重复的字符串元素组成。有序集合中的每个元素都关联了一个浮点值,称为分数。可以把有序看成hash和集合的混合体,分数即为hash的key。
- 有序集合中的元素是按序存储的,不是请求时才排序的。
- ZSet类型的操作类型
Hash-哈希
- redis的哈希值是字符串字段和字符串之间的映射,是表示对象的完美数据类型。
- 哈希中的字段数量没有限制,所以可以在你的应用程序以不同的方式来使用哈希。
- Hash类型的操作参考
springboot 与redis的整合
pom文件
依赖如下:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.1.RELEASE</version>
<relativePath/>
</parent>
<span ><<span >dependencies</span>></span>
<span ><!-- spring boot 配置 --></span>
<span ><<span >dependency</span>></span>
<span ><<span >groupId</span>></span>org.springframework.boot<span ></<span >groupId</span>></span>
<span ><<span >artifactId</span>></span>spring-boot-starter-web<span ></<span >artifactId</span>></span>
<span ></<span >dependency</span>></span>
<span ><<span >dependency</span>></span>
<span ><<span >groupId</span>></span>org.springframework.boot<span ></<span >groupId</span>></span>
<span ><<span >artifactId</span>></span>spring-boot-starter-thymeleaf<span ></<span >artifactId</span>></span>
<span ></<span >dependency</span>></span>
<span ><<span >dependency</span>></span>
<span ><<span >groupId</span>></span>org.springframework.boot<span ></<span >groupId</span>></span>
<span ><<span >artifactId</span>></span>spring-boot-starter-test<span ></<span >artifactId</span>></span>
<span ><<span >scope</span>></span>test<span ></<span >scope</span>></span>
<span ></<span >dependency</span>></span>
<span ><<span >dependency</span>></span>
<span ><<span >groupId</span>></span>org.springframework.boot<span ></<span >groupId</span>></span>
<span ><<span >artifactId</span>></span>spring-boot-starter-data-redis<span ></<span >artifactId</span>></span>
<span ></<span >dependency</span>></span>
<span ></<span >dependencies</span>></span>
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/**
• @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<<span >String</span>, <span >Object</span>> template = <span >new</span> RedisTemplate<>();
<span >// 配置连接工厂</span>
template.setConnectionFactory(<span >factory</span>);
<span >//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值(默认使用JDK的序列化方式)</span>
Jackson2JsonRedisSerializer jacksonSeial = <span >new</span> Jackson2JsonRedisSerializer(<span >Object</span>.<span >class</span>);
ObjectMapper om = <span >new</span> ObjectMapper();
<span >// 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public</span>
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
<span >// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常</span>
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSeial.setObjectMapper(om);
<span >// 值采用json序列化</span>
template.setValueSerializer(jacksonSeial);
<span >//使用StringRedisSerializer来序列化和反序列化redis的key值</span>
template.setKeySerializer(<span >new</span> StringRedisSerializer());
<span >// 设置hash key 和value序列化模式</span>
template.setHashKeySerializer(<span >new</span> StringRedisSerializer());
template.setHashValueSerializer(jacksonSeial);
template.afterPropertiesSet();
<span >return</span> 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;
importimport java.util.Collection;
import java.util.Date;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import@Component
public class RedisService{
@Autowired
private
<span >/**
* 默认过期时长,单位:秒
*/</span>
<span >public</span> <span >static</span> <span >final</span> <span >long</span> DEFAULT_EXPIRE = <span >60</span> * <span >60</span> * <span >24</span>;
<span >/**
* 不设置过期时长
*/</span>
<span >public</span> <span >static</span> <span >final</span> <span >long</span> NOT_EXPIRE = -<span >1</span>;
<span class="hljs-function"><span >public</span> <span >boolean</span> <span >existsKey</span><span class="hljs-params">(String key)</span> </span>{
<span >return</span> redisTemplate.hasKey(key);
}
<span >/**
* 重名名key,如果newKey已经存在,则newKey的原值被覆盖
*
* <span class="hljs-doctag">@param</span> oldKey
* <span class="hljs-doctag">@param</span> newKey
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >renameKey</span><span class="hljs-params">(String oldKey, String newKey)</span> </span>{
redisTemplate.rename(oldKey, newKey);
}
<span >/**
* newKey不存在时才重命名
*
* <span class="hljs-doctag">@param</span> oldKey
* <span class="hljs-doctag">@param</span> newKey
* <span class="hljs-doctag">@return</span> 修改成功返回true
*/</span>
<span class="hljs-function"><span >public</span> <span >boolean</span> <span >renameKeyNotExist</span><span class="hljs-params">(String oldKey, String newKey)</span> </span>{
<span >return</span> redisTemplate.renameIfAbsent(oldKey, newKey);
}
<span >/**
* 删除key
*
* <span class="hljs-doctag">@param</span> key
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >deleteKey</span><span class="hljs-params">(String key)</span> </span>{
redisTemplate.delete(key);
}
<span >/**
* 删除多个key
*
* <span class="hljs-doctag">@param</span> keys
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >deleteKey</span><span class="hljs-params">(String... keys)</span> </span>{
Set<String> kSet = Stream.of(keys).map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
<span >/**
* 删除Key的集合
*
* <span class="hljs-doctag">@param</span> keys
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >deleteKey</span><span class="hljs-params">(Collection<String> keys)</span> </span>{
Set<String> kSet = keys.stream().map(k -> k).collect(Collectors.toSet());
redisTemplate.delete(kSet);
}
<span >/**
* 设置key的生命周期
*
* <span class="hljs-doctag">@param</span> key
* <span class="hljs-doctag">@param</span> time
* <span class="hljs-doctag">@param</span> timeUnit
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >expireKey</span><span class="hljs-params">(String key, <span >long</span> time, TimeUnit timeUnit)</span> </span>{
redisTemplate.expire(key, time, timeUnit);
}
<span >/**
* 指定key在指定的日期过期
*
* <span class="hljs-doctag">@param</span> key
* <span class="hljs-doctag">@param</span> date
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >expireKeyAt</span><span class="hljs-params">(String key, Date date)</span> </span>{
redisTemplate.expireAt(key, date);
}
<span >/**
* 查询key的生命周期
*
* <span class="hljs-doctag">@param</span> key
* <span class="hljs-doctag">@param</span> timeUnit
* <span class="hljs-doctag">@return</span>
*/</span>
<span class="hljs-function"><span >public</span> <span >long</span> <span >getKeyExpire</span><span class="hljs-params">(String key, TimeUnit timeUnit)</span> </span>{
<span >return</span> redisTemplate.getExpire(key, timeUnit);
}
<span >/**
* 将key设置为永久有效
*
* <span class="hljs-doctag">@param</span> key
*/</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >persistKey</span><span class="hljs-params">(String key)</span> </span>{
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{
<span >public</span> <span >static</span> <span >final</span> String Table = <span >"t_user"</span>;
<span >private</span> String name;
<span >private</span> String address;
<span >private</span> Integer age;
<span class="hljs-function"><span >public</span> String <span >getName</span><span class="hljs-params">()</span> </span>{
<span >return</span> name;
}
<span class="hljs-function"><span >public</span> <span >void</span> <span >setName</span><span class="hljs-params">(String name)</span> </span>{
<span >this</span>.name = name;
}
<span class="hljs-function"><span >public</span> String <span >getAddress</span><span class="hljs-params">()</span> </span>{
<span >return</span> address;
}
<span class="hljs-function"><span >public</span> <span >void</span> <span >setAddress</span><span class="hljs-params">(String address)</span> </span>{
<span >this</span>.address = address;
}
<span class="hljs-function"><span >public</span> Integer <span >getAge</span><span class="hljs-params">()</span> </span>{
<span >return</span> age;
}
<span class="hljs-function"><span >public</span> <span >void</span> <span >setAge</span><span class="hljs-params">(Integer age)</span> </span>{
<span >this</span>.age = age;
}
<span >@Override</span>
<span class="hljs-function"><span >public</span> String <span >toString</span><span class="hljs-params">()</span> </span>{
<span >return</span> <span >"UserVo{"</span> +
<span >"name='"</span> + name + <span >'\''</span> +
<span >", address='"</span> + address + <span >'\''</span> +
<span >", age="</span> + age +
<span >'}'</span>;
}
}
再新建一个测试类:
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.*;
importimport
import java.util.Set;
importimport static
@RunWith(SpringRunner.class)
@SpringBootTest
public class RedisConfigTest{
<span >@Autowired</span>
<span >private</span> StringRedisTemplate stringRedisTemplate;
<span >@Autowired</span>
<span >private</span> RedisTemplate redisTemplate;
<span >@Resource</span>
<span >private</span> ValueOperations<String,Object> valueOperations;
<span >@Autowired</span>
<span >private</span> HashOperations<String, String, Object> hashOperations;
<span >@Autowired</span>
<span >private</span> ListOperations<String, Object> listOperations;
<span >@Autowired</span>
<span >private</span> SetOperations<String, Object> setOperations;
<span >@Autowired</span>
<span >private</span> ZSetOperations<String, Object> zSetOperations;
<span >@Resource</span>
<span >private</span> RedisService redisService;
<span >@Test</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >testObj</span><span class="hljs-params">()</span> <span >throws</span> Exception</span>{
UserVo userVo = <span >new</span> UserVo();
userVo.setAddress(<span >"上海"</span>);
userVo.setName(<span >"测试dfas"</span>);
userVo.setAge(<span >123</span>);
ValueOperations<String,Object> operations = redisTemplate.opsForValue();
redisService.expireKey(<span >"name"</span>,<span >20</span>, TimeUnit.SECONDS);
String key = RedisKeyUtil.getKey(UserVo.Table,<span >"name"</span>,userVo.getName());
UserVo vo = (UserVo) operations.get(key);
System.out.println(vo);
}
<span >@Test</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >testValueOption</span><span class="hljs-params">( )</span><span >throws</span> Exception</span>{
UserVo userVo = <span >new</span> UserVo();
userVo.setAddress(<span >"上海"</span>);
userVo.setName(<span >"jantent"</span>);
userVo.setAge(<span >23</span>);
valueOperations.set(<span >"test"</span>,userVo);
System.out.println(valueOperations.get(<span >"test"</span>));
}
<span >@Test</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >testSetOperation</span><span class="hljs-params">()</span> <span >throws</span> Exception</span>{
UserVo userVo = <span >new</span> UserVo();
userVo.setAddress(<span >"北京"</span>);
userVo.setName(<span >"jantent"</span>);
userVo.setAge(<span >23</span>);
UserVo auserVo = <span >new</span> UserVo();
auserVo.setAddress(<span >"n柜昂周"</span>);
auserVo.setName(<span >"antent"</span>);
auserVo.setAge(<span >23</span>);
setOperations.add(<span >"user:test"</span>,userVo,auserVo);
Set<Object> result = setOperations.members(<span >"user:test"</span>);
System.out.println(result);
}
<span >@Test</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >HashOperations</span><span class="hljs-params">()</span> <span >throws</span> Exception</span>{
UserVo userVo = <span >new</span> UserVo();
userVo.setAddress(<span >"北京"</span>);
userVo.setName(<span >"jantent"</span>);
userVo.setAge(<span >23</span>);
hashOperations.put(<span >"hash:user"</span>,userVo.hashCode()+<span >""</span>,userVo);
System.out.println(hashOperations.get(<span >"hash:user"</span>,userVo.hashCode()+<span >""</span>));
}
<span >@Test</span>
<span class="hljs-function"><span >public</span> <span >void</span> <span >ListOperations</span><span class="hljs-params">()</span> <span >throws</span> Exception</span>{
UserVo userVo = <span >new</span> UserVo();
userVo.setAddress(<span >"北京"</span>);
userVo.setName(<span >"jantent"</span>);
userVo.setAge(<span >23</span>);
// listOperations.leftPush(“list:user”,userVo);
// System.out.println(listOperations.leftPop(“list:user”));
// pop之后 值会消失
System.out.println(listOperations.leftPop(“list:user”));
}
}
注解缓存的使用
- @Cacheable:在方法执行前Spring先查看缓存中是否有数据,如果有数据,则直接返回缓存数据;没有则调用方法并将方法返回值放进缓存。
- @CachePut:将方法的返回值放到缓存中。
- @CacheEvict:删除缓存中的数据。