-
为什么使用缓存?
提升重复访问数据的访问效率。
-
Redis的三个用途
数据库,缓存,消息中间件
准备redis环境(win10)
https://github.com/microsoftarchive/redis/releases
下载安装包
用管理员方式运行cmd,安装软件:
在服务中确认redis正常启动
缓存是基于数据访问的,先写一个测试用的CRUD。
。。。
。。。
。。。
代码放这了,调一下数据库连接什么的先跑跑看…
https://github.com/HCJ-shadow/SpringBoot
1.添加Redis pom 依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-start-cache</artifactId></dependency>
2.配置Redis
spring:
datasource:
# 数据源基本配置
username: root
password: 564925080
driver-class-name: com.mysql.cj.jdbc.Driver
url: jdbc:mysql://localhost:3306/reference?serverTimezone=UTC
type: com.alibaba.druid.pool.DruidDataSource
# 数据源其他配置
initialSize: 5
minIdle: 5
maxActive: 20
maxWait: 60000
timeBetweenEvictionRunsMillis: 60000
minEvictableIdleTimeMillis: 300000
validationQuery: SELECT 1 FROM DUAL
testWhileIdle: true
testOnBorrow: false
testOnReturn: false
poolPreparedStatements: true
# 配置监控统计拦截的filters,去掉后监控界面sql无法统计,'wall'用于防火墙
filters: stat,wall,log4j
maxPoolPreparedStatementPerConnectionSize: 20
useGlobalDataSourceStat: true
connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
redis:
host: localhost
port: 6379
logging:
level:
zkrun.top.reference.mapper: debug
3.测试是否可用
@Autowired
StringRedisTemplate stringRedisTemplate;
@Test
public void testRedis()
{
stringRedisTemplate.opsForValue().append("ms","hello");
}
4.在主程序类中添加@EnableCaching注解
5.配置Redis序列化
package zkrun.top.reference.config;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import java.time.Duration;
@Configuration
@EnableCaching
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerialize 替换默认序列化
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
// 设置value的序列化规则和 key的序列化规则
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);
redisTemplate.afterPropertiesSet();
return redisTemplate;
}
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
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);
// 配置序列化(解决乱码的问题),过期时间30秒
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(1800000))
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
.disableCachingNullValues();
RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
.cacheDefaults(config)
.build();
return cacheManager;
}
}
7.常用缓存注解
@Cacheable
将方法运行结果进行缓存,当方法被再次调用时,直接返回缓存中的结果。
参数:
value:指定缓存组件的名字
key:缓存的key。可以使用SpEl表达式
condition:缓存条件。(为true时缓存),使用EL表达式
unless:否定缓存。(为true时不缓存)unless在方法执行之后判断,所以unless可以用结 果作为判断条件。
@CachePut
修改了数据库的数据,同时更新缓存。
先调用目标方法,然后缓存方法结果。
为保持同步,key需要设置和@Cacheable相同。
@CacheEvict 清除缓存
@CacheConfig 抽取公共配置
package zkrun.top.reference.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;
import zkrun.top.reference.bean.UserInfo;
import zkrun.top.reference.mapper.UserInfoMapper;
@CacheConfig(cacheNames="user") //抽取缓存公共配置
@Service
public class UserInfoService {
@Autowired
UserInfoMapper userInfoMapper;
@Cacheable(key="#id"/*,condition = "#id>1",unless = "#result.id<0"*/)
public UserInfo getUser(Integer id) {
System.out.println("find"+id);
UserInfo userInfo = userInfoMapper.getUserById(id);
return userInfo;
}
@CachePut(key="#result.id")
public UserInfo updateUser(UserInfo userInfo)
{
System.out.println("update"+userInfo);
userInfoMapper.updateUser(userInfo);
return userInfo;
}
@CacheEvict(key = "#id")
public void deleteUser(Integer id) {
userInfoMapper.deleteUserById(id);
}
}