springBoot与缓存
JSR107
java Caching五个核心接口:
CachingProvider:管理Cachemanager
CacheManager:定义了创建、配置、获取、管理控制多个Cache
Cache:类似map只被一个CacheManager拥有
Entry:是一个存储在Cache中的键值对
Expiry:缓存有效期
引入jar包
<dependency>
<groupId>javax.cache</groupId>
<artifactId>cache-api</artifactId>
</dependency>
spring缓存抽象
Cache:缓存
CacheManager 缓存管理,管理Cache
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存(查询方法)
@CacheEvict:清空缓存(删除方法)
@CachePut:保证方法被调用,有希望结果被缓存(更新方法)
@EnableCaching:开启基于注解的缓存(启动类)
keyGenerator缓存数据时key生成策略
serialize缓存数据时value序列化策略
使用缓存
1.开启缓存
启动类
@SpringBootApplication
@MapperScan("com.zhuoyue.mapper")
//开启缓存
@EnableCaching
public class ShoppingdemoApplication {
public static void main(String[] args) {
SpringApplication.run(ShoppingdemoApplication.class, args);
}
}
2.给方法开启缓存
@Cacheable 主要针对方法配置,能够根据方法的请求参数对其结果进行缓存(查询方法)
cacheNames/value:指定缓存的名字 ,将方法的返回结果放在哪个缓存中,是数组的方式,可以指定多个
key:缓存数据时使用的key,可以用它指定,默认使用方法的参数
keyGenerator:key的生成器和key互斥二选一
cacheManager:缓存管理器
condition:指定符合条件的情况下才缓存还可以像key一样使用Spel
unless:满足条件不缓存
sync:是否异步
@CacheEvict:清空缓存(删除方法)
@CachePut:保证方法被调用,有希望结果被缓存(更新方法)
@Override
@Cacheable(cacheNames = "emp")
public Page<DeptPO> findAll(PageDeptParam param) {
Page<DeptPO> page = new Page<>(param.getPageIndex(), param.getPageSize());
return lambdaQuery()
.like(param.getDname()!=null,DeptPO::getDname,param.getDname())
.like(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.le(param.getEndTime()!=null, DeptPO::getCreateTime,param.getEndTime())
.ge(param.getBeginTime()!=null,DeptPO::getCreateTime,param.getBeginTime())
.page(page);
}
缓存原理
自动配置原理
@Cacheable运行原理
@Cacheabled的其他属性
key的使用
@Override
@Cacheable(cacheNames = "emp",key="#p0.pageIndex")
public Page<DeptPO> findAll(PageDeptParam param) {
Page<DeptPO> page = new Page<>(param.getPageIndex(), param.getPageSize());
return lambdaQuery()
.like(param.getDname()!=null,DeptPO::getDname,param.getDname())
.like(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.le(param.getEndTime()!=null, DeptPO::getCreateTime,param.getEndTime())
.ge(param.getBeginTime()!=null,DeptPO::getCreateTime,param.getBeginTime())
.page(page);
}
keyGenerator
定义:
使用:
condition
指定符合条件的情况下才缓存
@Override
@Cacheable(cacheNames = "emp",condition="#p0.pageIndex>1")
public Page<DeptPO> findAll(PageDeptParam param) {
Page<DeptPO> page = new Page<>(param.getPageIndex(), param.getPageSize());
return lambdaQuery()
.like(param.getDname()!=null,DeptPO::getDname,param.getDname())
.like(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.le(param.getEndTime()!=null, DeptPO::getCreateTime,param.getEndTime())
.ge(param.getBeginTime()!=null,DeptPO::getCreateTime,param.getBeginTime())
.page(page);
}
unless
满足条件不缓存
@Override
@Cacheable(cacheNames = "emp",condition="#p0.pageIndex>1",unless="#p0.pageIndex>1")
public Page<DeptPO> findAll(PageDeptParam param) {
Page<DeptPO> page = new Page<>(param.getPageIndex(), param.getPageSize());
return lambdaQuery()
.like(param.getDname()!=null,DeptPO::getDname,param.getDname())
.like(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.le(param.getEndTime()!=null, DeptPO::getCreateTime,param.getEndTime())
.ge(param.getBeginTime()!=null,DeptPO::getCreateTime,param.getBeginTime())
.page(page);
}
sync 是否异步
@CachePut 更新缓存
@Override
@CachePut(cacheNames="dept",key = "#p0.id")
public DeptPO merge(MergeDeptParam param) {
lambdaUpdate()
.set(param.getDname()!=null,DeptPO::getDname,param.getDname())
.set(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.eq(DeptPO::getId,param.getId())
.update();
return lambdaQuery().eq(DeptPO::getId,param.getId()).one();
}
将修改后的数据放入缓存,如果key一样,查询时就去找缓存
@CacheEvict
根据指定cacheNames和指定key删除缓存
@Override
@CacheEvict(cacheNames = "dept",key = "#p0")
public void del(Long id) {
System.out.println("删除缓存数据!");
}
allEntity=true清楚所有缓存
@Override
@CacheEvict(cacheNames = "dept",key = "#p0",allEntity=true)
public void del(Long id) {
System.out.println("删除缓存数据!");
}
beforeInvocation = true方法之前清楚缓存,默认方法之后
@Override
@CacheEvict(cacheNames = "dept",key = "#p0",beforeInvocation = true)
public void del(Long id) {
System.out.println("删除缓存数据!");
}
@Caching
可配置缓存规则
@Override
@Caching(
cacheable = {
@Cacheable(cacheNames = "dept")
},
//方法运行之后
put = {
@CachePut(cacheNames = "dept",key = "#result.id")
}
)
public DeptPO merge(MergeDeptParam param) {
lambdaUpdate()
.set(param.getDname()!=null,DeptPO::getDname,param.getDname())
.set(param.getLoc()!=null,DeptPO::getLoc,param.getLoc())
.eq(DeptPO::getId,param.getId())
.update();
return lambdaQuery()
.eq(DeptPO::getId,param.getId())
.one();
}
@CacheConfig
类注解
放到类上可以指定统一的cacheNames
@Service
@CacheConfig(cacheNames = "dept")
public class DeptServiceImpl extends ServiceImpl<DeptMapper, DeptPO> implements DeptService {
}
集成redis
引入redis的jar包
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
写配置
spring:
redis:
host: 127.0.0.1
port: 6379
此时已经集成了redis的缓存,但是无法转换mybatis-plus的page
配置类
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
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.cache.RedisCacheWriter;
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.StringRedisSerializer;
import java.time.Duration;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.HashMap;
import java.util.Map;
/**
* @author Administrator
* @date 2022/1/10
*/
@Configuration
@EnableCaching
public class RedisConfig {
/**
* 申明缓存管理器,会创建一个切面(aspect)并触发Spring缓存注解的切点(pointcut)
* 根据类或者方法所使用的注解以及缓存的状态,这个切面会从缓存中获取数据,将数据添加到缓存之中或者从缓存中移除某个值
*
* @return
*/
/**
* 注解形式
*
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
return new RedisCacheManager(
RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
this.getRedisCacheConfigurationWithTtl(300), // 默认策略,未配置的 key 会使用这个
this.getRedisCacheConfigurationMap() // 指定 key 策略
);
}
private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
redisCacheConfigurationMap.put("getRolePermissions", this.getRedisCacheConfigurationWithTtl(300));
redisCacheConfigurationMap.put("getUser", this.getRedisCacheConfigurationWithTtl(60));
redisCacheConfigurationMap.put("getProject", this.getRedisCacheConfigurationWithTtl(60));
redisCacheConfigurationMap.put("getTeam", this.getRedisCacheConfigurationWithTtl(60));
// redisCacheConfigurationMap.put("UserInfoListAnother", this.getRedisCacheConfigurationWithTtl(18000));
return redisCacheConfigurationMap;
}
private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer seconds) {
Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
timeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
om.registerModule(timeModule);
jackson2JsonRedisSerializer.setObjectMapper(om);
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
RedisSerializationContext
.SerializationPair
.fromSerializer(jackson2JsonRedisSerializer)
).entryTtl(Duration.ofSeconds(seconds));
return redisCacheConfiguration;
}
/**
* 编程形式
*
* @param factory
* @return
*/
@Bean
public RedisTemplate redisTemplate(RedisConnectionFactory factory) {
// 创建一个模板类
RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
// 将刚才的redis连接工厂设置到模板类中
template.setConnectionFactory(factory);
// 设置key的序列化器
template.setKeySerializer(new StringRedisSerializer());
// 设置value的序列化器
//使用Jackson 2,将对象序列化为JSON
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
//json转对象类,不设置默认的会将json转成hashmap
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
//LocalDatetime序列化
JavaTimeModule timeModule = new JavaTimeModule();
timeModule.addDeserializer(LocalDate.class,
new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addDeserializer(LocalDateTime.class,
new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
timeModule.addSerializer(LocalDate.class,
new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd")));
timeModule.addSerializer(LocalDateTime.class,
new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
om.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
om.registerModule(timeModule);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
然后,可以用缓存注解开发。
标签:缓存,DeptPO,param,详解,new,import,null From: https://www.cnblogs.com/WangJingjun/p/16718006.html