首页 > 其他分享 >缓存详解

缓存详解

时间:2022-09-22 09:36:08浏览次数:61  
标签:缓存 DeptPO param 详解 new import null

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

相关文章

  • 装饰者模式、深拷贝、泛型序列化解决Caffeine中的缓存一致性问题
    一、前言Caffeine是一个高性能的Java缓存库,底层数据存储采用ConcurrentHashMap优点:因为Caffeine面向JDK8,在jdk8中ConcurrentHashMap增加了红黑树,在hash冲突严重时也......
  • linux命令:chmod(常用方法详解)
     linuxchmod命令是在日常运维中比较常用的命令之一,对文件管理比较重要,如设置web目录时需设置特定的权限以保证服务器安全。提示:在写完shell脚本后,我们一般需要给这脚本设......
  • FCKEditor配置及功能实现详解.
    ​ 在之前在工作中遇到在富文本编辑器中粘贴图片不能展示的问题,于是各种网上扒拉,终于找到解决方案,在这里感谢一下知乎中众大神以及TheViper。通过知乎提供的思路找到粘......
  • Linux中的一些命令详解
    一、命令行格式1.1、何为命令? 在Linux操作系统中,凡是在字符操作界面中输入能够完成特定操作和任务的字符串都可以称为命令命令通常只代表实现某一类功能的程序的名称......
  • require.context()的用法详解
    require.context(directory,useSubdirectories,regExp)directory:表示检索的目录seSubdirectories:表示是否检索子文件夹regExp:匹配文件的正则表达式,一般是文件名例......
  • MySQL主从同步详解与配置
    MySQL主从同步详解与配置走鹿带凨爱生活,有理想,善思考,能沟通 21人赞同了该文章 https://zhuanlan.zhihu.com/p/335142300MySQL主从同......
  • [踩坑回顾]html不使用浏览器缓存
    开发过程中遇到版本发布之后需要修改页面静态资源的问题,但由于初版没有设置不使用浏览器缓存,只好更换了页面地址。建议以后开发都在<head>中加上:<metahttp-equiv="......
  • df.drop_duplicates() 详解
     删除含有指定元素的行或列,或删除指定行,列用法:DataFrame.drop(labels=None,axis=0,index=None,columns=None,inplace=False)参数说明:labels就是要删除的行列的名字,......
  • Java无难事:详解Java编程核心思想与技术 pdf
    高清扫描版下载链接:https://pan.baidu.com/s/1Ht352zrCXy9ArE-Th9fgNg点击这里获取提取码 ......
  • Flex弹性布局详解
    简介FlexibleBox模型,通常被称为flexbox弹性盒子布局,是一种一维的布局模型。它给flexbox的子元素之间提供了强大的空间分布和对齐能力。我们说flexbox是一种一维的......