文章目录
SpringCache缓存框架
简介
- 官方地址https://spring.io/guides/gs/caching/
- 提供基本的Cache抽象,方便切换各种底层Cache,如Redis,caffeine
- 提供类似@Transactional注解事务的方式,类实现Cache
- 提供事务回滚时自动回滚缓存
- 核心
- Cache接口,缓存操作的API
- CacheManager管理各类缓存,有多个缓存框架的实现
使用
加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.5.3</version>
</dependency>
配置文件
选择缓存类型
spring:
cache:
type: redis
SpringBoot启动类开启缓存注解
@EnableCaching
SpringCache常用注解
@Cacheable
- value、cacheNames:两个等同的参数(cacheNames为Spring 4新增,作为value的别名),用于指定缓存存储的集合名。由于Spring 4中新增了@CacheConfig,因此在Spring 3中原本必须有的value属性,也成为非必需项了
- key:缓存对象存储在Map集合中的key值,非必需,缺省按照函数的所有参数组合作为key值,若自己配置需使用SpEL表达式,比如:@Cacheable(key = “#p0”):使用函数第一个参数作为缓存的key值,更多关于SpEL表达式的详细内容可参考官方文档
- condition:缓存对象的条件,非必需,也需使用SpEL表达式,只有满足表达式条件的内容才会被缓存,比如:@Cacheable(key = “#p0”, condition = “#p0.length() < 3”),表示只有当第一个参数的长度小于3的时候才会被缓存,
- unless:另外一个缓存条件参数,非必需,需使用SpEL表达式。它不同于condition参数的地方在于它的判断时机,该条件是在函数被调用之后才做判断的,所以它可以通过对result进行判断。
- keyGenerator:用于指定key生成器,非必需。若需要指定一个自定义的key生成器,我们需要去实现org.springframework.cache.interceptor.KeyGenerator接口,并使用该参数来指定。需要注意的是:该参数与key是互斥的
- cacheManager:用于指定使用哪个缓存管理器,非必需。只有当有多个时才需要使用
- cacheResolver:用于指定使用那个缓存解析器,非必需。需通过org.springframework.cache.interceptor.CacheResolver接口来实现自己的缓存解析器,并用该参数指定。
@CachePut
@CachePut 的作用 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用
@CacheEvict
@CachEvict 的作用 主要针对方法配置,能够根据一定的条件对缓存进行清空,主要用作删除
@Caching
有时候我们可能组合多个Cache注解使用;比如用户新增成功后,我们要添加id–>user;username—>user;email—>user的缓存;此时就需要@Caching组合多个注解标签了。
@Caching(put = {
@CachePut(value = "user", key = "#user.id"),
@CachePut(value = "user", key = "#user.username"),
@CachePut(value = "user", key = "#user.email")
})
public User save(User user) {
}
@CacheConfig
所有的@Cacheable()里面都有一个value=“xxx”的属性,这显然如果方法多了,写起来也是挺累的,如果可以一次性声明完 那就省事了, 所以,有了@CacheConfig这个配置,@CacheConfig is a class-level annotation that allows to share the cache names,如果你在你的方法写别的名字,那么依然以方法的名字为准。
@CacheConfig是一个类级别的注解
SpringBoot+MyBatisPlus+H2+SpringCache+Redis整合使用
依赖引入
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.3</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<version>2.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.baomidou</groupId>
<artifactId>mybatis-plus-boot-starter</artifactId>
<version>3.4.3.4</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
h2,初始化SQL脚本
data-h2.sql
DELETE FROM user;
INSERT INTO user (id, name, age, email) VALUES
(1, 'Jone', 18, 'test1@baomidou.com'),
(2, 'Jack', 20, 'test2@baomidou.com'),
(3, 'Tom', 28, 'test3@baomidou.com'),
(4, 'Sandy', 21, 'test4@baomidou.com'),
(5, 'Billie', 24, 'test5@baomidou.com');
INSERT INTO user2 (id, name, age) VALUES
(1, 'Jone', 18),
(2, 'Jack', 20),
(3, 'Tom', 28),
(4, 'Sandy', 21),
(5, 'Billie', 24);
schema-h2.sql
DROP TABLE IF EXISTS user;
CREATE TABLE user
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
email VARCHAR(50) NULL DEFAULT NULL COMMENT '邮箱',
PRIMARY KEY (id)
);
CREATE TABLE user2
(
id BIGINT(20) NOT NULL COMMENT '主键ID',
name VARCHAR(30) NULL DEFAULT NULL COMMENT '姓名',
age INT(11) NULL DEFAULT NULL COMMENT '年龄',
PRIMARY KEY (id)
);
yml配置
spring:
cache:
type: redis
#H2配置
datasource:
driver-class-name: org.h2.Driver
url: jdbc:h2:mem:test
username: root
password: test
#H2初始化
sql:
init:
#表结构
schema-locations: classpath:db/schema-h2.sql
#表数据
data-locations: classpath:db/data-h2.sql
redis:
host: Redis地址
password: Redis密码
database: 0
mybatis-plus:
configuration:
log-impl: org.apache.ibatis.logging.stdout.StdOutImpl #开启sql日志
主启动类
@SpringBootApplication
@MapperScan("com.peppa.springcache.mapper")
@ComponentScan("com.peppa")
@EnableCaching
public class SpringCacheTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringCacheTestApplication.class, args);
}
}
CacheConfig类
其中配置了RedisCacheManager
@Configuration
public class CacheConfig {
@Bean
@Primary
public RedisCacheManager cacheManager1Hour(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config=instanceConfig(3600L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
@Bean
public RedisCacheManager cacheManager1Min(RedisConnectionFactory connectionFactory){
RedisCacheConfiguration config=instanceConfig(60L);
return RedisCacheManager.builder(connectionFactory)
.cacheDefaults(config)
.transactionAware()
.build();
}
private RedisCacheConfiguration instanceConfig(Long ttl){
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
objectMapper.registerModule(new JavaTimeModule());
//去掉各种@JsonSerialize的注解的解析
objectMapper.configure(MapperFeature.USE_ANNOTATIONS,false);
//只针对非空值进行序列化
objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
//将类型序列化到属性json字符串中
objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
jackson2JsonRedisSerializer.setObjectMapper(objectMapper);
return RedisCacheConfiguration.defaultCacheConfig()
.entryTtl(Duration.ofSeconds(ttl))
.disableCachingNullValues()
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer));
}
}
/*
自定义缓存Key规则
*/
@Bean
public KeyGenerator springCacheCustomeKeyGenerator(){
return new KeyGenerator(){
@override
public Object generate(Object o,Method method,Object... objects){
retrun o.getClass().getSimpleName()+"_"
+method.getName()+"_"
+ StringUtils.arrayToDelimitedString(objects,"_");
}
}
}
KeyGenerator
Entity类
User
@Data
@Builder
//一定要序列化,Redis存储必须序列化实体类
public class User implements Serializable {
private Long id;
private String name;
private Integer age;
private String email;
}
Mapper
@Mapper
public interface UserMapper extends BaseMapper<User> {
}
Service
@Service
public class UserService {
@Autowired
UserMapper userMapper;
@Cacheable(value = {"user"},key = "#root.methodName",cacheManager = "cacheManager1Min")
public List<User> select(){
List<User> users = userMapper.selectList(null);
return users;
}
@CachePut(value = {"user"},key = "#root.args[0]")
public User insert(Long id){
User user = User.builder().id(id).build();
int insert = userMapper.insert(user);
return user;
}
@Cacheable(value = {"user"},keyGenerator="springCacheCustomeKeyGenerator")
public User selectOne(Long id){
User user = userMapper.selectById(id);
return user;
}
@CacheEvict(value = {"user"},key = "#root.args[0]")
public int delete(Long id){
int insert = userMapper.deleteById(id);
return insert;
}
}
本文介绍了如何在SpringBoot应用中整合SpringCache和Redis,包括依赖配置、常用注解的使用方法、以及在MyBatisPlus和H2环境下的整合步骤。重点讲解了@Cacheable、@CachePut、@CacheEvict和@Caching的实战应用以及CacheConfig的配置优化。
320

被折叠的 条评论
为什么被折叠?



