redis概述
Redis可以存储键与5种不同数据结构类型之间的映射,这5种数据结构类型分别为
STRING(字符串)、LIST(列表)、SET(集合)、HASH(散列)和ZSET(有序集合)。
有一部分Redis命令对于这5种结构都是通用的,如DEL、TYPE、RENAME等;但也有一部分Redis命令只能对特定的一种或者两种结构使用;
一些数据库和缓存服务器的特性与功能
名称 | 类型 | 数据存储选项 | 查询类型 | 附加功能 |
---|---|---|---|---|
Redis | 使用内存存储(in-memory)的非关系数据库 | 字符串、列表、集合、散列表、有序集合 | 每种数据类型都有自己的专属命令,另外还有批量操作(bulk operation)和不完全(partial)的事务支持 | 发布与订阅,主从复制(master/slave replication),持久化,脚本(存储过程,stored procedure) |
memcached | 使用内存存储的键值缓存 | 键值之间的映射 | 创建命令、读取命令、更新命令、删除命令以及其他几个命令 | 为提升性能而设的多线程服务器 |
MySQL | 关系数据库 | 每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图(view);支持空间(spatial)和第三方扩展 | SELECT、 INSERT、 UPDATE、 DELETE、函数、存储过程 | 支持ACID性质(需要使用InnoDB),主从复制和主主复制 (master/master replication) |
PostgreSQL | 关系数据库 | 每个数据库可以包含多个表,每个表可以包含多个行;可以处理多个表的视图;支持空间和第三方扩展;支持可定制类型 | SELECT、 INSERT、 UPDATE、 DELETE、内置函数、自定义的存储过程 | 支持ACID性质,主从复制,由第三方支持的多主复制(multi-master replication) |
MongoDB | 使用硬盘存储(on-disk)的非关系文档存储 | 每个数据库可以包含多个表,每个表可以包含多个无schema(schema-less)的BSON文档 | 创建命令、读取命令、更新命令、删除命令、条件查询命令等 | 支持map-reduce操作,主从复制,分片,空间索引(spatial index) |
==表格样式不是我能决定的,凑合看吧==
Redis提供的5种结构
结构类型 | 结构存储的值 | 结构的读写能力 |
---|---|---|
STRING | 可以是字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作;对整数和浮点数执行自增(increment)或者自减(decrement)操作 |
LIST | 一个链表,链表上的每个节点都包含了一个字符串 | 从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值查找或者移除元素 |
SET | 包含字符串的无序收集器(unordered collection),并且被包含的每个字符串都是独一无二、各不相同的 | 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对;获取所有键值对 |
ZSET(有序集合) | 字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定 | 添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素 |
redis特性
源码简单 ,约23000行C语言源代码。
- 速度快
Redis是用C语言实现的;Redis的所有数据存储在内存中,用于快速地读写访问。 - 持久化
Redis的所有数据存储在内存中,对数据的更新将异步地保存到磁盘上;
redis的持久化有两种方式:AOF与RDB两种模式 - 支持多种数据结构
Redis支持五种数据结构:String、List、Set、Hash、Zset - 支持多种编程语言
Java、php、Python、Ruby、Lua、Node.js等 - 功能丰富
除了支持五种数据结构之外,还支持缓存、事务、流水线、发布/订阅、消息队列等功能。
发布/订阅模型: Redis支持创建发布和订阅通道,这样Redis客户端可以订阅任意的通道来进行数据消费,并且任何已订阅该通道的客户端可以发布数据。 - 主从复制
主服务器(master)执行写入(增删改),从(slave)服务器执行查询。复制提供可伸缩性和可用性。任何一个slave宕机,其他的slave还可以提供数据访问。 - 虚拟内存
Redis使用RAM作为内存式存储。但是,在内存不足的情况下,它使用虚拟内存来保存数据。 - 高可用及分布式
Redis-Sentinel(v2.8)支持高可用
Redis-Cluster(v3.0)支持分布式
redis部分命令
flushdb:清空当前数据库;
select [index]:选择索引数据库,index为索引值名,如:select 1;
del [key]:删除一条指定key的值;
keys *:查看数据库内所有的key;
flushall:清空所有数据库;
quit:退出客户端连接。
==友情提示:部分命令慎用,线上一定不能用==
redis安装
redis下载安装
- windows版本下载:https://github.com/MicrosoftArchive/redis/releases ,目前是redis-3.2.100版本。
- 解压下载的zip压缩包:
Redis on Windows.docx:关于Redis的描述文档
redis.windeows.conf:默认的配置文件
RedisService.docx:安装手册
redis-server.exe:redis服务启动执行文件
redis-cli.exe:redis客户端启动执行文件 - 注册redis服务到本机系统中
在当前redis解压文件目录下...\Redis-x64-3.2.100\,本机系统中注册服务:
redis-server --service-install redis.windows.conf --loglevel verbose
卸载服务:
redis-server --service-uninstall
启动Redis:
redis-server.exe
指定配置文件启动,适用于多个redis数据库的时候
redis-server.exe redis.windows.conf停止Redis:
redis-server --service-stop安装成功:
![]()
启动redis:
- redis客户端测试
- 双击redis客户端执行文件:redis-cli.exe
- 测试:ping
redis桌面可视化工具
- Redis可视化工具,RedisDesktopManager
它是开源的,托管在github上:https://github.com/uglide/RedisDesktopManager
下载地址:https://redisdesktop.com/download - 安装:双击默认安装
- 连接测试:
redis Java客户端
redis支持的语言,可在官网查看!重点看下redis的java客户端jedis:
github地址:https://github.com/xetorthio/jedis
spring boot 整合redis
spring boot整合redis有两种方式:
其一:使用外部配置,通过jedis技术框架实现;
其二:通过spring boot提供的数据访问框架Spring Data Redis实现,它是基于Jedis的。
第一种方式,可以参考SSM框架整合jedis进行操作配置;重点是第二种实现方式!
spring data redis
通过spring boot中的redis自动配置类,关于redis自动配置类RedisAutoConfiguration.java
//排除redis自动配置注解
@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class)
查看其源码:
spring boot在Spring Data Redis提供了两个模板:
- RedisTemplate
- StringRedisTemplate
RedisTemplate会使用JdkSerializationRedisSerializer处理数据,这意味着key和value都会通过Java进行序列化。
StringRedisTemplate默认会使用StringRedisSerializer处理数据。
要是操作字符串的话,用StringRedisTemplate就可以满足。但要是想要存储一个对象Object,我们就需要使用RedisTemplate,并对key采用String序列化方式,对value采用json序列化方式,这时候就需要对redisTemplate自定义配置,项目源码片段:
/**
* 实例化 RedisTemplate 对象
*
* @return RedisTemplate
*/
@Bean
public RedisTemplate<String, Object> functionDomainRedisTemplate() {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(redisConnectionFactory);
initDomainRedisTemplate(redisTemplate);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
/**
* 设置数据存入 redis 的序列化方式
* </br>redisTemplate 序列化默认使用的jdkSerializeable, 存储二进制字节码, 导致key会出现乱码,所以自定义
* 序列化类
*
* @param redisTemplate
* @param factory
*/
private void initDomainRedisTemplate(RedisTemplate<String, Object> redisTemplate) {
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
string结构的数据,设置value的序列化规则和 key的序列化规则
//StringRedisSerializer解决key中乱码问题。//Long类型不可以会出现异常信息;
redisTemplate.setKeySerializer(new StringRedisSerializer());
//value乱码问题:Jackson2JsonRedisSerializer
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
//设置Hash结构的key和value的序列化方式
//redisTemplate.setHashKeySerializer(jackson2JsonRedisSerializer);
//redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
}
RedisTempalte类API
方 法 | 子API接口 | 描 述 |
---|---|---|
opsForValue() | ValueOperations<K, V> | 操作具有简单值的条目 |
opsForList() | ListOperations<K, V> | 操作具有list值的条目 |
opsForSet() | SetOperations<K, V> | 操作具有set值的条目 |
opsForZSet() | ZSetOperations<K, V> | 操作具有ZSet值(排序的set)的条目 |
opsForHash() | HashOperations<K, HK, HV> | 操作具有hash值的条目 |
boundValueOps(K) | BoundValueOperations<K,V> | 以绑定指定key的方式,操作具有简单值的条目 |
boundListOps(K) | BoundListOperations<K,V> | 以绑定指定key的方式,操作具有list值的条目 |
boundSetOps(K) | BoundSetOperations<K,V> | 以绑定指定key的方式,操作具有set值的条目 |
boundZSet(K) | BoundZSetOperations<K,V> | 以绑定指定key的方式,操作具有ZSet值(排序的set)的条目 |
boundHashOps(K) | BoundHashOperations<K,V> | 以绑定指定key的方式,操作具有hash值的条目 |
spring boot缓存管理
spring boot集成redis进行数据缓存功能;有两种实现:
1,通过在代码中调用redis API实现数据的CRUD;
【参考RedisUtils工具类,该工具类支持redis的其他业务场景】
2,通过在方法上添加缓存注解实现;
【重点介绍,只支持redis作为缓存管理时使用】
Spring 提供了很多缓存管理器,例如:
- SimpleCacheManager
- EhCacheCacheManager
- CaffeineCacheManager
- GuavaCacheManager
- CompositeCacheManager
- RedisCacheManager Spring Data提供的缓存管理器:RedisCacheManager
在Spring Boot中通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),默认情况下Spring Boot根据下面的顺序自动检测缓存提供者:
- Generic
- JCache (JSR-107)
- EhCache 2.x
- Hazelcast
- Infinispan
- Redis
- Guava
- Simple
因为之前已经配置了RedisTemplate了,Spring Boot就无法自动给RedisCacheManager设置RedisTemplate了,所以要自己配置CacheManager。
1, 修改RedisConfig配置类,添加@EnableCaching注解,并继承CachingConfigurerSupport,重写CacheManager 方法:
/**
* 实例化 CacheManager 对象,指定使用RedisCacheManager作缓存管理
*
* @return CacheManager
*/
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
// 设置缓存过期时间(单位:秒),60秒
rcm.setDefaultExpiration(120);
return rcm;
}
Spring提供了如下注解来声明缓存规则:
- @Cacheable triggers cache population
- @cacheevict triggers cache eviction
- @cacheput updates the cache without interfering with the method execution
- @caching regroups multiple cache operations to be applied on a method
- @cacheconfig shares some common cache-related settings at class-level
注 解 | 描 述 |
---|---|
@Cacheable | 表明Spring在调用方法之前,首先应该在缓存中查找方法的返回值。如果这个值能够找到,就会返回缓存的值。否则的话,这个方法就会被调用,返回值会放到缓存之中 |
@cacheput | 表明Spring应该将方法的返回值放到缓存中。在方法的调用前并不会 检查缓存,方法始终都会被调用 |
@cacheevict | 表明Spring应该在缓存中清除一个或多个条目 |
@caching | 这是一个分组的注解,能够同时应用多个其他的缓存注解 |
@cacheconfig | 可以在类层级配置一些共用的缓存配置 |
@Cacheable和@cacheput有一些共有的属性:
属 性 | 类 型 | 描 述 |
---|---|---|
value | String[] | 要使用的缓存名称 |
condition | String | SpEL表达式,如果得到的值是false的话,不会将缓存应用到方法调用上 |
key | String | SpEL表达式,用来计算自定义的缓存key |
unless | String | SpEL表达式,如果得到的值是true的话,返回值不会放到缓存之中 |
2, 通过注解@Cacheable,对数据进行缓存处理:
代码片段:
/**
* 通过缓存注解,添加数据到redis中
* </br>实现数据缓存!
* @param cat 对象
*/
@Cacheable
@RequestMapping(value = "/getCat/{catId}", method = RequestMethod.GET)
@ResponseBody
public Cat add(@PathVariable("catId") int catId){
return this.catService.getCat(catId);
}
注意:Cat对象必须实现implements Serializable接口!
启动访问:http://127.0.0.1:8066/redis/getCat/1
java.lang.IllegalStateException: No cache could be resolved for 'Builder[public com.wyait.redis.pojo.Cat com.wyait.redis.controller.RedisCacheController.add(int)] caches=[] | key='' | keyGenerator='' | cacheManager='' | cacheResolver='' | condition='' | unless='' | sync='false'' using resolver 'org.springframework.cache.interceptor.SimpleCacheResolver@5e67a11d'. At least one cache should be provided per cache operation.
at org.springframework.cache.interceptor.CacheAspectSupport.getCaches(CacheAspectSupport.java:244) ~[spring-context-4.3.13.RELEASE.jar:4.3.13.RELEASE]
这个错误,是由于@Cacheable注解没有指定缓存名称导致的。加上value值,再试:
@Cacheable(value = "catCache")
测试访问成功!多次访问,走redis缓存。
3, redis缓存key生成策略
键的生成策略有两种,一种是默认策略,一种是自定义策略。
-
----------------------------默认策略:
If no params are given, return SimpleKey.EMPTY. If only one param is given, return that instance. If more the one param is given, return a SimpleKey containing all parameters.
默认的key是通过KeyGenerator生成的,其默认策略如下:
1.如果方法没有参数,则使用0作为key;
2.如果只有一个参数的话则使用该参数作为key;
3.如果参数多于一个则使用所有参数的hashcode作为key; - ----------------------------自定义策略:
自定义策略是指我们通过Spring的EL表达式来指定我们的key。这里的EL表达式可以使用参数以及它们对应的属性。使用方法参数时我们可以直接使用“#参数名”或者“#p参数index”。
之前在redisTemplate里设置了template.setKeySerializer(new StringRedisSerializer()),需要key是string类型。也可以使用SpEL表达式生成Key,
(SpEL表达式:http://itmyhome.com/spring/expressions.html)
返回结果需要是string类型(比如#root.methodName就是,#root.method不是String),通用办法是重写keyGenerator定制Key默认生成策略(按照缓存名称+id方式生成key,同时确保更新操作的时候,操作的是同一条数据),也可以在使用缓存注解时指定key:
/**
* 指定key的生成策略
* @return KeyGenerator
*/
@Bean public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override public Object generate(Object target, Method method,
Object... params) {
StringBuilder sb = new StringBuilder();
String[] value = new String[1];
// sb.append(target.getClass().getName());
// sb.append(":" + method.getName());
Cacheable cacheable = method.getAnnotation(Cacheable.class);
if (cacheable != null) {
value = cacheable.value();
}
CachePut cachePut = method.getAnnotation(CachePut.class);
if (cachePut != null) {
value = cachePut.value();
}
CacheEvict cacheEvict = method.getAnnotation(CacheEvict.class);
if (cacheEvict != null) {
value = cacheEvict.value();
}
sb.append(value[0]);
//获取参数值
for (Object obj : params) {
sb.append(":" + obj.toString());
}
return sb.toString();
}
};
}
注意:
1,在使用缓存注解时,也可以指定统一规则的key
(比如:@Cacheable(value = "catCache", key = "#root.caches[0].name + ':' + #id"));
就可以不走KeyGenerator默认规则;同样可以实现,更新和查询都是同一个key的数据;
2,使用注解进行数据缓存,指定数据过期时间需要百度普及下!
4, 更新缓存数据
更新与删除Redis缓存需要用到@cacheput和@cacheevict。必须保证keyGenerator生成同一个key,否则更新的不是同一条的数据;
/**
* 更新redis中的缓存数据
*</br> #root. 是spEL表达式
* </br>如果参数是个对象,就通过“#对象.变量”获取到对应的key中需要的值;比如:#cat.id
* @param id 主键
*/
@CachePut(value = "catCache", key = "#root.caches[0].name + ':' + #id")
@RequestMapping(value = "/updateCat", method = RequestMethod.POST)
@ResponseBody
public Cat update(@RequestParam int id){
System.out.println("==========请求参数:"+id);
return this.catService.updateCat(id);
}
本文转自 wyait 51CTO博客,原文链接:http://blog.51cto.com/wyait/2048478,如需转载请自行联系原作者