SpringBoot集成SpringCache
banner 2020-11-01 SpringBootSpringCache
# 一、pom.xml引入jar包
<!-- Spring Cache -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
1
2
3
4
5
2
3
4
5
# 二、开启@EnableCaching注解
在启动类或者SpringCache配置类上添加@EnableCaching
注解开启缓存功能。
@Configuration
@EnableCaching //启动 Cache 功能
public class SpringCacheConfig {
}
1
2
3
4
5
2
3
4
5
# 三、配置数据库和redis连接
spring:
jpa:
show-sql: true
hibernate:
ddl-auto: update
database-platform: org.hibernate.dialect.MySQL5InnoDBDialect
datasource:
url: jdbc:mysql://127.0.0.1:3306/spring-cache?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf-8&useSSL=true
redis:
host: 127.0.0.1
port: 6379
database: 1
lettuce:
pool:
max-active: 8
min-idle: 0
# Date格式化
jackson:
date-format: yyyy-MM-dd HH:mm:ss
time-zone: GMT+8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
# 四、配置CacheManager
在👆的 SpringCacheConfig
类中增加CacheManager配置
@Configuration
@EnableCaching //启动 Cache 功能
public class SpringCacheConfig extends CachingConfigurerSupport {
private final ObjectMapper om = new ObjectMapper();
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
RedisCacheManager redisCacheManager = new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
// 默认策略,未配置的 key 会使用这个
this.getRedisCacheConfigurationWithTtl(60 * 5),
// 指定 key 策略
this.getRedisCacheConfigurationMap()
);
redisCacheManager.setTransactionAware(true);
return redisCacheManager;
}
public static final String DATE_FORMAT_10 = "yyyy-MM-dd";
public static final String DATE_FORMAT_19 = "yyyy-MM-dd HH:mm:ss";
/**
* 处理LocalDateTime的JavaTimeModule
*/
private JavaTimeModule javaTimeModule() {
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT_10)));
javaTimeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DATE_FORMAT_19)));
javaTimeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT_10)));
javaTimeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DATE_FORMAT_19)));
return javaTimeModule;
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL);
//解决时间序列化问题
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(javaTimeModule());
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(jackson2JsonRedisSerializer)
).entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>(16);
redisCacheConfigurationMap.put("users", this.getRedisCacheConfigurationWithTtl(5 * 60));//自定义设置缓存时间
return redisCacheConfigurationMap;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
# 五、使用缓存注解
@Service
@CacheConfig(cacheNames = {"users"})
public class UserService {
@Resource
private UserRepository userRepository;
@Cacheable(key = "'user.all'") // 标志读取缓存操作,如果缓存不存在,则调用目标方法,并将结果放入缓存
public List<User> all() {
return userRepository.findAll();
}
@Cacheable(key = "#id")//如果缓存存在,直接读取缓存值;如果缓存不存在,则调用目标方法,并将结果放入缓存
public User info(Long id) {
return userRepository.findById(id).orElse(null);
}
@CachePut(key = "#user.id")//写入缓存,key为user.id,一般该注解标注在新增方法上
@Transactional
public User add(User user) {
return userRepository.save(user);
}
@CacheEvict(key = "#user.id")//根据key清除缓存,一般该注解标注在修改和删除方法上
@Transactional
public void update(User user) {
userRepository.save(user);
}
@CacheEvict(allEntries = true)//移除所有数据
public void deleteAll1() {
}
@CacheEvict(beforeInvocation = true)//方法调用前清空所有缓存
public void deleteAll2() {
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# 六、LocalDateTime问题
没有配置 时间序列化 时,会报错以下异常
//解决时间序列化问题
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(javaTimeModule()); //看上面的配置
1
2
3
2
3
com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Cannot construct instance of `java.time.LocalDateTime` (no Creators, like default construct, exist): cannot deserialize from Object value (no delegate- or property-based Creator)
at [Source: (byte[])"["java.util.ArrayList",[["top.banner.entity.User",{"id":1,"username":"张三","password":null,"groupId":1,"age":null,"updateTime":["java.sql.Timestamp",1603933940000],"createTime":{"date":{"year":2020,"month":"OCTOBER","day":29,"monthValue":10,"dayOfMonth":29,"dayOfWeek":"THURSDAY","era":["java.time.chrono.IsoEra","CE"],"dayOfYear":303,"leapYear":true,"chronology":{"calendarType":"iso8601","id":"ISO"},"prolepticMonth":24249},"time":{"hour":9,"minute":12,"second":20,"nano":0},"year":2020,"month":"[truncated 8311 bytes]; line: 1, column: 182] (through reference chain: java.util.ArrayList[0]->top.banner.entity.User["createTime"])
1
2
3
2
3