文章目录
1. 准备
- 创建SpringBoot工程并引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
- 配置连接信息(无密码)
sprin:
redis:
host: 127.0.0.1
port: 6379
2. 基于注解的缓存实现
spring boot为我们提供了一套缓存注解, 用于解决Service层的缓存问题, 很方便的让我们为Service层加入缓存
2.1 开启注解(配置类中或者启动类中)让缓存生效
@EnableCaching
@SpringBootApplication
public class SpringDataRedisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataRedisApplication.class, args);
}
}
2.2 使用注解配置, 添加, 更新, 删除缓存(Service 案例)
MySQL操作默认使用的是MybatisPlus进行操作
@Service
@CacheConfig(cacheNames = {"usersCache"}) // 配置缓存键的命名方式 ==> usersCache::1
public class UsersServiceImpl extends ServiceImpl<UsersMapper, UsersEntity> implements UsersService {
@Resource
private UsersServiceImpl usersService;
@Override // 不缓存空值
@Cacheable(key = "#id", unless = "#id==null")
public UsersEntity findUsersById(Long id) {
return usersService.getById(id);
}
@Override // 不更新空值
@CachePut(key = "#usersEntity.id", unless = "#usersEntity.id==null")
public UsersEntity updateUsersById(UsersEntity usersEntity) {
if (!usersService.updateById(usersEntity))
throw new RuntimeException("更新失败");
return usersEntity;
}
@Override
@CacheEvict(key = "#id")
public void deleteUserById(Long id) {
if (!usersService.removeById(id))
throw new RuntimeException("删除失败");
}
}
注意: 缓存对象必须实现序列化(Serializable接口), 因为默认使用的是JDK序列化方式
@Data
@ToString
@TableName("users")
public class UsersEntity implements Serializable {
private Long id;
private String name;
private Integer age;
private Boolean sex;
private String address;
}
说明: 也可以自定义序列化方式和全局缓存失效时间, 在RedisConfig中进行配置, 如下
3. 基于Redis操作模板类的缓存实现
3.1 使用默认的操作模板类
注意: 缓存的自定义对象要实现序列化接口
// 缓存demo对象
@Data
@NoArgsConstructor
@AllArgsConstructor
@ToString
public class Users implements Serializable {
private String name;
private int age;
}
//------------------------------------------------------------
// 使用默认提供的RedisTemplate<Object,Object>
@Autowired
private RedisTemplate<Object,Object> objectTemplate;
// 使用默认提供的 StringRedisTemplate
@Autowired
private StringRedisTemplate stringTemplate;
@Test
void contextLoads() {
// 从模板中获取String name - value类型的操作对象
ValueOperations<Object, Object> valueOperations = objectTemplate.opsForValue();
valueOperations.set("user1",users);
Users user1 = (Users)valueOperations.get("user1");
System.out.println( "获取反序列化对象" + user1);
// 使用String name - value对象的List结构
ListOperations<String, String> stringListOperations = stringTemplate.opsForList();
stringListOperations.leftPush("myList","从左边加入一个value值");
System.out.println(stringListOperations.rightPop("myList"));
}
3.2 使用自定义的操作模板类(自定义序列化方式)
因为使用JDK默认的序列化, 序列化出的对象尺寸更大, 而且在可视化工具上显示会乱码, 并且每个自定义序列化对象如都必须实现Serializable接口, 因此我们有必要自定义序列化对象.
- 第一步创建配置文件, 自定义 RedisTemplate Bean
/**
* @ClassName: RedisTemplateConfig
* @Author zhangjin
* @Date 2021/6/28 15:14
* @Description: 自定义 RedisTemplate + 配置缓存管理器(作用于注解缓存)
*/
@Configuration
public class RedisConfig {
/**
* 自定义Key为String类型Value为Object类型的Redis操作模板
* 注意SpringDataRedis本身提供了: StringRedisTemplate, RedisTemplate<Object,Object> 两个不同类型的操作模板
*/
@Bean(name = "stringByObjectTemplate")
public RedisTemplate<String, Object> stringByObjectTemplate(RedisConnectionFactory redisConnectionFactory) {
RedisTemplate<String,Object> template = new RedisTemplate<>();
template.setConnectionFactory(redisConnectionFactory);
//自定义Jackson序列化配置
Jackson2JsonRedisSerializer<Object> jsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
jsonRedisSerializer.setObjectMapper(objectMapper);
//自定义String序列化配置
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
//key使用String的序列化方式
template.setKeySerializer(stringRedisSerializer);
//hash的key也是用String的序列化方式
template.setHashKeySerializer(stringRedisSerializer);
//value的key使用jackson的序列化方式
template.setValueSerializer(jsonRedisSerializer);
//hash的value也是用jackson的序列化方式
template.setHashValueSerializer(jsonRedisSerializer);
//配置完之后将所有的properties设置进去
template.afterPropertiesSet();
return template;
}
/**
* cacheManager 缓存管理器, 有关缓存的配置都在这里进行配置
* 修改注解缓存序列化方式, 不使用JDK默认的序列化方式
* 参考: https://www.cnblogs.com/yanlong300/p/11905978.html
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory factory) {
GenericJackson2JsonRedisSerializer genericJackson2JsonRedisSerializer = new GenericJackson2JsonRedisSerializer();
StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
// 获取缓存默认配置对象
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 配置自定义序列化特性和失效时间
RedisCacheConfiguration redisCacheConfiguration = config
// 键序列化方式 redis字符串序列化 值序列化方式 简单json序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(stringRedisSerializer))
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(genericJackson2JsonRedisSerializer))
// 配置缓存失效时间 60秒
.entryTtl(Duration.ofSeconds(60));
return RedisCacheManager.builder(factory).cacheDefaults(redisCacheConfiguration).build();
}
}
- 测试
@Autowired
@Qualifier(value = "stringByObjectTemplate")
private RedisTemplate<String,Object> customTemplate;
@Test
void testSerialize() {
ValueOperations<String, Object> opsForValue = customTemplate.opsForValue();
opsForValue.set("user",users);
Users user = (Users)opsForValue.get("user");
System.out.println("获取反序列化对象" + user);
}
4. 注意点/完整项目地址
无论是使用自定义模缓存对象还是基于注解实现缓存都必须在序列化配置中对java8的时间对象
进行配置, 否则无法正常进行序列化和反序列化.