本文共 11442 字,大约阅读时间需要 38 分钟。
上一篇博客:
Redis是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库。
redis官网:
redis中文网:
书籍参阅:《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) |
==表格样式不是我能决定的,凑合看吧==
结构类型 | 结构存储的值 | 结构的读写能力 |
---|---|---|
STRING | 可以是字符串、整数或者浮点数 | 对整个字符串或者字符串的其中一部分执行操作;对整数和浮点数执行自增(increment)或者自减(decrement)操作 |
LIST | 一个链表,链表上的每个节点都包含了一个字符串 | 从链表的两端推入或者弹出元素;根据偏移量对链表进行修剪(trim);读取单个或者多个元素;根据值查找或者移除元素 |
SET | 包含字符串的无序收集器(unordered collection),并且被包含的每个字符串都是独一无二、各不相同的 | 添加、获取、移除单个元素;检查一个元素是否存在于集合中;计算交集、并集、差集;从集合里面随机获取元素 |
HASH | 包含键值对的无序散列表 | 添加、获取、移除单个键值对;获取所有键值对 |
ZSET(有序集合) | 字符串成员(member)与浮点数分值(score)之间的有序映射,元素的排列顺序由分值的大小决定 | 添加、获取、删除单个元素;根据分值范围(range)或者成员来获取元素 |
源码简单 ,约23000行C语言源代码。
flushdb:清空当前数据库;
select [index]:选择索引数据库,index为索引值名,如:select 1; del [key]:删除一条指定key的值; keys *:查看数据库内所有的key; flushall:清空所有数据库; quit:退出客户端连接。 ==友情提示:部分命令慎用,线上一定不能用==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的java客户端jedis:
github地址:
spring boot整合redis有两种方式:
其一:使用外部配置,通过jedis技术框架实现; 其二:通过spring boot提供的数据访问框架Spring Data Redis实现,它是基于Jedis的。第一种方式,可以参考SSM框架整合jedis进行操作配置;重点是第二种实现方式!
通过spring boot中的redis自动配置类,关于redis自动配置类RedisAutoConfiguration.java
//排除redis自动配置注解@EnableAutoConfiguration(exclude = RedisAutoConfiguration.class)
查看其源码:
spring boot在Spring Data Redis提供了两个模板:
RedisTemplate会使用JdkSerializationRedisSerializer处理数据,这意味着key和value都会通过Java进行序列化。
StringRedisTemplate默认会使用StringRedisSerializer处理数据。要是操作字符串的话,用StringRedisTemplate就可以满足。但要是想要存储一个对象Object,我们就需要使用RedisTemplate,并对key采用String序列化方式,对value采用json序列化方式,这时候就需要对redisTemplate自定义配置,项目源码片段:
/** * 实例化 RedisTemplate 对象 * * @return RedisTemplate */ @Bean public RedisTemplatefunctionDomainRedisTemplate() { RedisTemplate redisTemplate = new RedisTemplate<>(); redisTemplate.setConnectionFactory(redisConnectionFactory); initDomainRedisTemplate(redisTemplate); redisTemplate.afterPropertiesSet(); return redisTemplate; } /** * 设置数据存入 redis 的序列化方式 * redisTemplate 序列化默认使用的jdkSerializeable, 存储二进制字节码, 导致key会出现乱码,所以自定义 * 序列化类 * * @param redisTemplate * @param factory */ private void initDomainRedisTemplate(RedisTemplate 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); }
方 法 | 子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集成redis进行数据缓存功能;有两种实现:
1,通过在代码中调用redis API实现数据的CRUD; 【参考RedisUtils工具类,该工具类支持redis的其他业务场景】 2,通过在方法上添加缓存注解实现; 【重点介绍,只支持redis作为缓存管理时使用】Spring 提供了很多缓存管理器,例如:
在Spring Boot中通过@EnableCaching注解自动化配置合适的缓存管理器(CacheManager),默认情况下Spring Boot根据下面的顺序自动检测缓存提供者:
因为之前已经配置了RedisTemplate了,Spring Boot就无法自动给RedisCacheManager设置RedisTemplate了,所以要自己配置CacheManager。
1, 修改RedisConfig配置类,添加@EnableCaching注解,并继承CachingConfigurerSupport,重写CacheManager 方法:
/** * 实例化 CacheManager 对象,指定使用RedisCacheManager作缓存管理 * * @return CacheManager */@Beanpublic CacheManager cacheManager(RedisTemplate redisTemplate) { RedisCacheManager rcm = new RedisCacheManager(redisTemplate); // 设置缓存过期时间(单位:秒),60秒 rcm.setDefaultExpiration(120); return rcm;}
Spring提供了如下注解来声明缓存规则:
注 解 | 描 述 |
---|---|
@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中 * 实现数据缓存! * @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接口!
启动访问: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;之前在redisTemplate里设置了template.setKeySerializer(new StringRedisSerializer()),需要key是string类型。也可以使用SpEL表达式生成Key,
(SpEL表达式:) 返回结果需要是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中的缓存数据 * #root. 是spEL表达式 * 如果参数是个对象,就通过“#对象.变量”获取到对应的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); }
5, 测试//TODO
wyait-redis项目源码:
github:
码云:spring boot系列文章:
转载于:https://blog.51cto.com/wyait/2048478