springboot整合redis学习笔记

版权声明:本文为博主原创文章,欢迎转载! https://blog.csdn.net/qq_36336332/article/details/82875853

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 当前被调用的对象的class root.targetClass
args 当前方法参数组成的数组 root.args[0]
caches 当前被调用的方法使用的Cache root.caches[0].name

猜你喜欢

转载自blog.csdn.net/qq_36336332/article/details/82875853