springboot-cache

几个概念

Cahce:缓存接口,定义缓存操作。实现的有RedisCache、EhCache、ConcurrentMapCache等;

CacheManager:缓存管理器,管理各种缓存组件,默认使用ConcurrentMapCacheManager;

@Cacheable:主要加在方法上,能够缓存方法的返回结果(方法的结果缓存后,下一次调用该方法将不执行,直接从缓存中获取同一对象 );

    value:缓存组件名,将结果放在哪个缓存中,可多个

    key:缓存数据的key,默认使用方法参数的值,可指定spel表达式

    keyGenerator:指定自定义的key生成器    

    condition:满足条件的可缓存

    unless:为true时不缓存

    cacheManager:指定缓存管理器。

@CacheEvict:清除缓存;

      allEntries:true清除全部,false不清除全部

      beforeInvocation:是否在方法执行之前清除缓存,针对方法执行过程中出现异常

@Cacheput:保证方法被调用,而且缓存方法的返回结果;

      key要与@Cacheable中指定的key一样才能防止@Cacheable方法再次调用执行,而且指定的CacheManager要相同。

@Caching:定义复杂的缓存规则;

@EableCaching:主配置类上,开启基于注解的缓存;

@CacheConfig:在类上,抽取缓存公共配置,指定缓存组件:cacheNames(可多个),指定cacheManager,指定key的生成器:keyGenerator

KeyGenerator:缓存数据时,key的生成策略;

serialize:缓存数据时,value的序列化策略。

基于注解的ConcurrentMapCache

在未引入其他缓存依赖的情况下,springboot默认使用ConcurrentMapCache,使用注解时的CacheManager为必须,默认为ConcurrentMapCacheManager

注解中能使用的cache表达式:

自定义缓存key生成器 keyGenerator:

@Configuration
public class TestConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new BasicDataSource();
    }

    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            // 方法名,传入参数
            public Object generate(Object o, Method method, Object... objects) {
                return method.getName() + Arrays.asList(objects);
            }
        };
    }
}

 使用:

@CacheConfig(cacheNames = "xzqh")// 指定使用xzqh名字的缓存组件
@Service
public class TestService {
    @Autowired
    TestMapper testMapper;

    @Cacheable(key = "#root.args[0]",cacheManager = "concurrentMapCacheManager")// 指定使用的缓存管理器,key的生成策略
    public Object query(String qhbm){
        System.out.println("查询:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        return xzqh;
    }

    // 使用指定的key生成器
    @Cacheable(keyGenerator = "keyGenerator")
    public Xzqh add(Xzqh xzqh){
        testMapper.add(xzqh);
        return xzqh;
    }

    @CachePut(key = "#root.args[0].qhbm")
    public Xzqh update(Xzqh xzqh){
        System.out.println("修改:1231231"+xzqh.getQhbm());
        testMapper.update(xzqh);

        return xzqh;
    }

    @CacheEvict(key = "#root.args[0]",allEntries = false)
    public void delete(String qhbm){
        System.out.println("删除:"+qhbm);
        testMapper.delete(qhbm);
    }

    @Caching(cacheable = {@Cacheable(key = "#pqhbm")},put = {@CachePut(key = "#result.qhbm"),@CachePut(key = "#result.qhjb")})
    public Xzqh getByPqhbm(String pqhbm){
        System.out.println("查询父编码:"+pqhbm);
        return testMapper.queryByPqhbm(pqhbm);
    }

}

单独使用Redis

1. 引入redis依赖

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>

底层还是Jedis!

2. 配置redis连接

spring.redis.host=101.297.0.51
spring.redis.port=8888

3. 使用StringRedisTemplate或者RedisTemplate操作缓存

StringRedisTemplate针对操作字符串,RedisTemplate能操作各种数据类型,存储对象必须实现序列化接口,否则报错,而默认使用的是JDK序列化方式,这种序列化存储的结果是一串阅读不友好的字符,改使用json的序列化方式。

springboot 2.x后的序列化方式:

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        //连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        // 序列化配置 解析任意对象
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // json序列化利用ObjectMapper进行转义
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //指定要序列化的域,filed,get和set、Any是包括private// 和public
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        // 2.序列化String类型
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);

        return template;
    }

使用RedisTemplate:

@Service
public class TestService {
    @Autowired
    TestMapper testMapper;

    @Autowired
    RedisTemplate redisTemplate;

    public Xzqh query1(String qhbm){
        System.out.println("查询1:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        redisTemplate.opsForHash().put("tem",qhbm,xzqh);
        redisTemplate.opsForValue().set("killo","2000公里");
        return xzqh;
    }
    public Xzqh query2(String qhbm){
        System.out.println("查询2:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        redisTemplate.opsForHash().put("tem",qhbm,xzqh);
        Xzqh tem = (Xzqh) redisTemplate.opsForHash().get("tem", qhbm);

        System.out.println(tem.toString());
        return xzqh;
    }
}

基于注解的RedisCache

缓存自动配置类:CacheAutoConfiguration,默认使用SimpleCacheConfiguration产生ConcurrentMapCacheManager,引入redis依赖后,将使用RedisCacheConfiguration产生RedisCacheManager。

注解方式需要有CacheManager,CacheManager调用缓存操作工具执行缓存操作。

所以需要自定义配置RedisCacheManager和RedisTemplate(json序列化),也可使用默认的。

@Configuration
public class TestConfig {

    @Bean
    @ConfigurationProperties(prefix = "spring.datasource")
    public DataSource dataSource() {
        return new BasicDataSource();
    }

    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object o, Method method, Object... objects) {
                return method.getName() + Arrays.asList(objects);
            }
        };
    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        //连接工厂
        template.setConnectionFactory(redisConnectionFactory);

        // 序列化配置 解析任意对象
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        // json序列化利用ObjectMapper进行转义
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); //指定要序列化的域,filed,get和set、Any是包括private// 和public
//        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);//
        jackson2JsonRedisSerializer.setObjectMapper(om);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);

        // 2.序列化String类型
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);

        return template;
    }

    @Bean
    public RedisCacheManager redisCacheManager(RedisConnectionFactory factory) {
        RedisCacheManager redisCacheManager =
                RedisCacheManager.builder(factory)
                        .cacheDefaults(defaultCacheConfig(10000))
                        .transactionAware()
                        .build();
        return redisCacheManager;
    }

    private RedisCacheConfiguration defaultCacheConfig(Integer second) {
        Jackson2JsonRedisSerializer<Object> serializer =
                new Jackson2JsonRedisSerializer<>(Object.class);
        ObjectMapper mapper = new ObjectMapper();
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
//        mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(mapper);

        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(second))
                .serializeKeysWith(RedisSerializationContext
                        .SerializationPair
                        .fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(
                        RedisSerializationContext
                                .SerializationPair
                                .fromSerializer(serializer))
                .disableCachingNullValues();
        return config;
    }
}

CacheManager和RedisTemplate可同时使用:

@CacheConfig(cacheNames = "xzqh")
@Service
public class TestService {
    @Autowired
    TestMapper testMapper;

    @Autowired
    RedisTemplate redisTemplate;

    public Xzqh query1(String qhbm){
        System.out.println("查询1:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        redisTemplate.opsForHash().put("tem",qhbm,xzqh);
        redisTemplate.opsForValue().set("killo","2000公里");
        return xzqh;
    }
    public Xzqh query2(String qhbm){
        System.out.println("查询2:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        redisTemplate.opsForHash().put("tem",qhbm,xzqh);
        Xzqh tem = (Xzqh) redisTemplate.opsForHash().get("tem", qhbm);

        System.out.println(tem.toString());
        return xzqh;
    }

    /**
     * 之所以使用Object而不使用对应的实体接收,是因为从缓存中读取已存在的数据不能够自动转化成对应的实体
     * @param qhbm
     * @return
     */
    @Cacheable(key = "#root.args[0]",cacheManager = "redisCacheManager")
    public Object query(String qhbm){
        System.out.println("查询:"+qhbm);
        Xzqh xzqh = testMapper.getXzqh(qhbm);
        return xzqh;
    }

    public void add(Xzqh xzqh){
        testMapper.add(xzqh);
    }

    @CachePut(key = "#root.args[0].qhbm")
    public Xzqh update(Xzqh xzqh){
        System.out.println("修改:1231231"+xzqh.getQhbm());
        testMapper.update(xzqh);

        return xzqh;
    }

    @CacheEvict(key = "#root.args[0]",allEntries = false)
    public void delete(String qhbm){
        System.out.println("删除:"+qhbm);
        testMapper.delete(qhbm);
    }

    @Caching(cacheable = {@Cacheable(key = "#pqhbm")},put = {@CachePut(key = "#result.qhbm"),@CachePut(key = "#result.qhjb")})
    public Xzqh getByPqhbm(String pqhbm){
        System.out.println("查询父编码:"+pqhbm);
        return testMapper.queryByPqhbm(pqhbm);
    }

}

之所以使用Object而不使用对应的实体接收,是因为从缓存中读取已存在的数据不能够自动转化成对应的实体

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值