springboot整合redis学习笔记

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

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

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

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

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

 

1、引入依赖: 



	org.springframework.boot
	spring-boot-starter-data-redis

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 functionDomainRedisTemplate() {
	// 方法名为 redisTemplate ,key才不会乱码
	public RedisTemplate redisTemplate() {
		RedisTemplate redisTemplate = new RedisTemplate<>();
		redisTemplate.setConnectionFactory(redisConnectionFactory);
		initDomainRedisTemplate(redisTemplate);
		redisTemplate.afterPropertiesSet();
		return redisTemplate;
	}

	/**
	 * 设置数据存入 redis 的序列化方式 
* redisTemplate 序列化默认使用的jdkSerializeable, 存储二进制字节码, 所以自定义序列化类 * * @param redisTemplate */ 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); // 使用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 valueOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForValue(); } /** * 实例化 HashOperations 对象,可以使用 Hash 类型操作 * * @param redisTemplate * @return */ @Bean public HashOperations hashOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForHash(); } /** * 实例化 ListOperations 对象,可以使用 List 操作 * * @param redisTemplate * @return */ @Bean public ListOperations listOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForList(); } /** * 实例化 SetOperations 对象,可以使用 Set 操作 * * @param redisTemplate * @return */ @Bean public SetOperations setOperations(RedisTemplate redisTemplate) { return redisTemplate.opsForSet(); } /** * 实例化 ZSetOperations 对象,可以使用 ZSet 操作 * * @param redisTemplate * @return */ @Bean public ZSetOperations zSetOperations(RedisTemplate 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 getComplainList(CalendarInDTO complain) {

//		String key = complain.getStartTime() + "," + complain.getEndTime();
//		List 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 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 当前被调用的对象的class root.targetClass
args 当前方法参数组成的数组 root.args[0]
caches 当前被调用的方法使用的Cache root.caches[0].name

你可能感兴趣的:(缓存)