springboot整合redis学习笔记

Redis实现缓存添加,更新和删除的方法有很多.

1:较为笨拙的方法,也是最稳定的方法,也是一些自动化缓存更新的原理但是代码就多了点,在需要用到缓存的地方,去判断,

         先从缓存取,取不到,去数据库查找,找到返回该数据,并写入缓存

2:使用aop的思想,在需要用到缓存的地方左上标识(用注解实现即可,方法很多),剩下的原理同上,这是个一劳永逸的过程

3:就是这篇文章要讲的:使用spring自带的Cacheable注解处理Redis缓存,以下为具体的细节描述

 

1、引入依赖: 

<!-- springboot整合redis -->
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

2、在配置文件中配置 Redis 源:

# redis
########################################################
###REDIS (RedisProperties) redis基本配置
########################################################
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器IP
spring.redis.host=127.0.0.1
# Redis密码(默认为空)
spring.redis.password=
# Redis端口号
spring.redis.port=6379
# 连接超时时间 单位 ms(毫秒)
spring.redis.timeout=3000
########################################################
###REDIS (RedisProperties) redis线程池设置
########################################################
# 控制一个pool最多有多少个状态为idle(空闲的)的jedis实例,默认值也是8。
spring.redis.pool.max-idle=8
# 控制一个pool最少有多少个状态为idle(空闲的)的jedis实例,默认值也是0。
spring.redis.pool.min-idle=2
# 如果赋值为-1,则表示不限制;如果pool已经分配了maxActive个jedis实例,则此时pool的状态为exhausted(耗尽)。
spring.redis.pool.max-active=20
# 等待可用连接的最大时间,单位毫秒,默认值为-1,表示永不超时。如果超过等待时间,则直接抛出JedisConnectionException
spring.redis.pool.max-wait=3000
#默认生命周期30天(单位:s秒)
spring.redis.defaultExpiration=2592000
#服务器上下文路径
spring.redis.contextPath=contextPath

 3、RedisConfig配置类:

package com.mobile.mobilemap.manage.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.*;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.KeyGenerator;
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;

import java.lang.reflect.Method;

/**
 * 继承CachingConfigurerSupport,重写CacheManager方法。
 */
@Configuration
@EnableCaching // (缓存支持)
public class RedisConfig extends CachingConfigurerSupport {
	private Logger logger = LoggerFactory.getLogger(this.getClass());

	/**
	 * 注入 RedisConnectionFactory
	 */
	@Autowired
	RedisConnectionFactory redisConnectionFactory;

	/**
	 * 指定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];
				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();
			}
		};
	}

	/**
	 * 实例化 CacheManager 对象,指定使用RedisCacheManager作缓存管理
	 *
	 * @return CacheManager
	 */
	@Bean
	public CacheManager cacheManager(RedisTemplate redisTemplate) {
		RedisCacheManager rcm = new RedisCacheManager(redisTemplate);
		// 设置缓存过期时间(单位:秒),60秒
		rcm.setDefaultExpiration(600);
		return rcm;
	}

	/**
	 * 实例化 RedisTemplate 对象
	 *
	 * @return RedisTemplate
	 */
	@Bean
//	public RedisTemplate<String, Object> functionDomainRedisTemplate() {
	// 方法名为 redisTemplate ,key才不会乱码
	public RedisTemplate<String, Object> redisTemplate() {
		RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		initDomainRedisTemplate(redisTemplate);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}

	/**
	 * 设置数据存入 redis 的序列化方式 </br>
	 * redisTemplate 序列化默认使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类
	 *
	 * @param redisTemplate
	 */
	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);
		// 使用StringRedisSerializer来序列化和反序列化redis的key值
		redisTemplate.setKeySerializer(new StringRedisSerializer());
		// value乱码问题:Jackson2JsonRedisSerializer
		redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
	}

	/**
	 * redis数据操作异常处理 这里的处理:在日志中打印出错误信息,但是放行
	 * 保证redis服务器出现连接等问题的时候不影响程序的正常运行,使得能够出问题时不用缓存
	 *
	 * @return
	 */
	@Bean
	@Override
	public CacheErrorHandler errorHandler() {
		CacheErrorHandler cacheErrorHandler = new CacheErrorHandler() {
			@Override
			public void handleCacheGetError(RuntimeException e, Cache cache, Object key) {
				logger.error("redis异常:key=[{}]", key, e);
			}

			@Override
			public void handleCachePutError(RuntimeException e, Cache cache, Object key, Object value) {
				logger.error("redis异常:key=[{}]", key, e);
			}

			@Override
			public void handleCacheEvictError(RuntimeException e, Cache cache, Object key) {
				logger.error("redis异常:key=[{}]", key, e);
			}

			@Override
			public void handleCacheClearError(RuntimeException e, Cache cache) {
				logger.error("redis异常:", e);
			}
		};
		return cacheErrorHandler;
	}

	/**
	 * 实例化 ValueOperations 对象,可以使用 String 操作
	 *
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForValue();
	}

	/**
	 * 实例化 HashOperations 对象,可以使用 Hash 类型操作
	 *
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForHash();
	}

	/**
	 * 实例化 ListOperations 对象,可以使用 List 操作
	 *
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForList();
	}

	/**
	 * 实例化 SetOperations 对象,可以使用 Set 操作
	 *
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForSet();
	}

	/**
	 * 实例化 ZSetOperations 对象,可以使用 ZSet 操作
	 *
	 * @param redisTemplate
	 * @return
	 */
	@Bean
	public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
		return redisTemplate.opsForZSet();
	}

}

4、使用例子:放到service层上:

	@Override
	@Cacheable(value="ComplainServiceImpl",key="'getComplainList'.concat(#complain.startTime.toString()).concat(#complain.endTime.toString())", unless = "#result eq null")
	public List<BcomplainOutDTO> getComplainList(CalendarInDTO complain) {

//		String key = complain.getStartTime() + "," + complain.getEndTime();
//		List<BcomplainOutDTO> list = redisTemplate.opsForValue().get(key);
//		System.out.println("从缓存中获取 = " + list);
//		if (redisTemplate.hasKey(key)) {
//
//			System.out.println("==== 从缓存中获取了投诉数据! ====");
//			return list;
//		}
//		list = complainMapper.getComplainList(complain);
//
//		// 缓存100秒
//		redisTemplate.opsForValue().set(key, list, 100, TimeUnit.SECONDS);
//
//		return list;

		return complainMapper.getComplainList(complain);
	}

放到dao层上:

@Cacheable(value="getWorkDetailPhotos",key="'getWorkDetailPhotos'.concat(#root.args[0])")
List<String> getWorkDetailPhotos(Integer workId);

缓存的清除:如果我们缓存的实体更新了,怎么办?不能够get的还是旧的东西。这时候就需要强制清除相关联的缓存了。方法就是提供一个空的接口方法,在该方法上添加@CacheEvict的注解,如下:

@CacheEvict(value = "workDetailV150", allEntries=true)
public void evictWorkDetailCache(){
 
}

5、注意事项:
    1)、redis和mysql数据的同步,代码级别大致可以这样做:
    2)、读: 读redis->没有,读mysql->把mysql数据写回redis
    3)、写: 写mysql->成功,写redis
    4)、特别注意的是这里的注入,由于之前配置了redisTemplate及其子类,故需要使用@Resource注解进行!

6、RedisTemplate中定义了对5种数据结构操作:
    1)、redisTemplate.opsForValue();//操作字符串
    2)、redisTemplate.opsForHash();//操作hash
    3)、redisTemplate.opsForList();//操作list
    4)、redisTemplate.opsForSet();//操作set
    5)、redisTemplate.opsForZSet();//操作有序set

7、Cacheable注解key的说明:来源https://blog.csdn.net/u011271894/article/details/77969070

这个地方主要简单说明一下3个要素:1.字符串、2.接口参数、3.环境参数,以及一个函数
字符串很好说了用单引号括起来就可以了。
接口参数直接用#加参数名,如果是参数内的属性那么继续用.串联接好了。
环境参数:

属性名称描述示例
methodName当前方法名root.methodName
method当前方法root.method.name
target当前被调用的对象root.target
targetClass当前被调用的对象的classroot.targetClass
args当前方法参数组成的数组root.args[0]
caches当前被调用的方法使用的Cacheroot.caches[0].name
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
整理自尚硅谷视频教程springboot高级篇,并增加部分springboot2.x的内容 一、Spring Boot与缓存 一、JSR107 Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry 和 Expiry。 • CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可 以在运行 期访问多个CachingProvider。 • CacheManager定义了创建、配置、获取、管理和控制多个唯一命名 的Cache,这些Cache 存在于CacheManager的上下文中。一个CacheManager仅被一个 CachingProvider所拥有。 • Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个 Cache仅被一个 CacheManager所拥有。 • Entry是一个存储在Cache中的key-value对。 • Expiry 每一 个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期 的状态。一旦过期,条 目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。 二、Spring缓存抽象 Spring从3.1开始定义了org.springframework.cache.Cache 和 org.springframework.cache.CacheManager接口来统一不同的缓存技术; 并支持使用JCache(JSR- 107)注解简化我们开发; • Cache接口为缓存的组件规范定义,包含缓存的各种操作集合; • Cache接 口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache , ConcurrentMapCache 等; • 每次调用需要缓存功能的方法时,Spring会检查检查指定参数的指定的目标方法是否 已经被调用 过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法 并缓存结果后返回给用户。下 次调用直接从缓存中获取。 • 使用Spring缓存抽象时我们需要关注以下两点; 1、确定方法需要被缓存 以及他们的缓存策略 2、从缓存中读取之前缓存存储的数据 Cache 缓存接口,定义缓存操作。实现有:RedisCache、EhCacheCache、 ConcurrentMapCache等 CacheManager 缓存管理器,管理各种缓存(Cache)组件 @Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存 @CacheEvict 清空缓存 @CachePut 保证方法被调用,又希望结果被缓存。 @EnableCaching 开启基于注解的缓存 keyGenerator 缓存数据时key生成策略 serialize 缓存数据时value序列化策略 @CacheConfig 抽取缓存的公共配置 三、几个重要概念&缓存注解 1、常用注解 2、常用参数 名字 位置 描述 示例 methodName root object 当前被调用的方法名 #root.methodName method root object 当前被调用的方法 #root.method.name target root object 当前被调用的目标对象 #root.target targetClass root object 当前被调用的目标对象类 #root.targetClass args root object 当前被调用的方法的参数列表 #root.args[0] 3、常用参数SPEL说明 名字 位置 描述 示例 caches root object 当前方法调用使用的缓存列表(如 @Cacheable(value= {"cache1","cache2"}) ), 则有两 个cache #root.caches[0].name argument name evaluation context 方法参数的名字. 可以直接 #参数 名 ,也可以使用 #p0或#a0 的形 式,0代表参数的索引; #iban 、 #a0 、 #p0 result evaluation context 方法执行后的返回值(仅当方法执 行之后的判断有效,如‘unless’ , ’cache put’的表达式 ’cache evict’的表达式 beforeInvocation=false ) #result 四、代码中使用缓存 1、搭建基本环境 1、导入数据库文件 创建出department和employee表 2、创建javaBean封装数据 3、整合MyBatis操作数据库 1.配置数据源信息 2.使用注解版的MyBatis; 1)、@MapperScan指定需要扫描的mapper接口所在的包

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ljt-tiger

thanks

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值