springboot缓存

一.JSR107缓存(了解)

Java Caching定义了5个核心接口,分别是CachingProvider, CacheManager, Cache, Entry和Expiry。

  1. CachingProvider定义了创建、配置、获取、管理和控制多个CacheManager。一个应用可以在运行期访问多个CachingProvider。
  2. CacheManager定义了创建、配置、获取、管理和控制多个唯一命名的Cache,这些Cache存在于CacheManager的上下文中。一个CacheManager仅被一个CachingProvider所拥有。
  3. Cache是一个类似Map的数据结构并临时存储以Key为索引的值。一个Cache仅被一个CacheManager所拥有。
  4. Entry是一个存储在Cache中的key-value对。
  5. Expiry每一个存储在Cache中的条目有一个定义的有效期。一旦超过这个时间,条目为过期的状态。一旦过期,条目将不可访问、更新和删除。缓存有效期可以通过ExpiryPolicy设置。

在这里插入图片描述
使用JSR107需要导入如下包

<dependency>
    <groupId>javax.cache</groupId>
    <artifactId>cache-api</artifactId>
</dependency>

二.spring缓存(简化了JSR-107缓存)

1.Spring从3.1开始定义了Cache和CacheManager接口来统一不同的缓存技术;并支持使用JCache(JSR-107)注解简化我们开发;

  • Cache接口为缓存的组件规范定义,包含缓存的各种操作集合;

  • Cache接口下Spring提供了各种xxxCache的实现;如RedisCache,EhCacheCache 、ConcurrentMapCache等;

  • 每次调用需要缓存功能的方法时,Spring会检查指定参数的指定的目标方法是否已经被调用过;如果有就直接从缓存中获取方法调用后的结果,如果没有就调用方法并缓存结果后返回给用户。下次调用直接从缓存中获取。

  • 使用Spring缓存抽象时我们需要关注以下两点;

    • 确定方法需要被缓存以及他们的缓存策略
    • 从缓存中读取之前缓存存储的数据

2.spring中常用的注解
在这里插入图片描述
3.常用属性
@Cacheable:作用于方法上,执行方法对结果进行缓存(若是有该缓存,则不用进入该方法).常用语查询的方法上面
@CacheEvice:删除缓存,常用户删除方法
@CachePut:更新缓存,常用于更新方法

下面是其属性值:
常用值:
1.cacheNames/value:给该缓存取名字(必须要)
2.key 缓存是存储key value的形式,所以给key取个名族,不写,系统自己取(遵循SPEL)

会生成一个key为方法名[参数id]
在这里插入图片描述
2.keyGenerator与key两者选择一个
自定义一个keyGenerator的bean,加载到容器中

package com.wcy.springbootcache.config;

import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.lang.reflect.Method;
import java.util.Arrays;

@Configuration
public class MyCacheConfig {

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

在这里插入图片描述
3.cacheManager、cacheResolver生成缓存
3.condition:方法之前执行,条件为true则缓存(遵循SPEL)

在这里插入图片描述
4.unless:方法之后完,条件为false则缓存(遵循SPEL)
5.sync是否采取异步

CacheEvict可以用:
6.allEntries删除cacheName下的所有缓存
7.beforeInvocation在方法之前删除,若为true如果方法里面出现异常,缓存还是会被删除,若为false,则方法出现异常不用清空缓存

下图:
在这里插入图片描述
在这里插入图片描述
遵循SPEL,上图属性可以选择下面的属性
在这里插入图片描述
4.springboot使用缓存:

  1. 导入缓存的启动器
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
  1. @EnableCaching开启缓存
    在这里插入图片描述
  2. 方法上使用注解:
    1.@Cacheable的使用:
    /*
    
该方法如果有缓存不会执行
    key缓存的key
    condition:id>1才缓存
    unless不为空才缓存
    keyGenerator = "myKeyGenerator"自定义的keyGenerator的配置类
     */
    @Cacheable(cacheNames = {"emp","test"},key = "#id",condition = "#id>1",unless = "#result==null")
    @Override
    public Employee findEmployeeById(Integer id) {
        System.out.println("查询成功");
        return employeeMapper.findEmployeeById(id);
    }

2.@CachePut的使用:

    /*
    CachePut注解该方法必执行,并更新缓存,不过注意key与Cacheable的key相同才行
     */
    @CachePut(cacheNames = {"emp"},key = "#employee.id")
    @Override
    public Employee editEmployee(Employee employee) {
        System.out.println("更新了数据");
        employeeMapper.editEmployee(employee);
        return employee;
    }

3.@CacheEvict的用法

    /*
    CacheEvict删除缓存,指定key删除
    allEntries删除cacheName下的所有缓存
    beforeInvocation在方法之前删除,若为true如果方法里面出现异常,缓存还是会被删除,若为false,则方法出现异常不用清空缓存
     */
     @CacheEvict(cacheNames = {"emp","test"},key = "#id" /*,allEntries = true,beforeInvocation = true*/)
    @Override
    public Integer deleteEmployee(Integer id) {
        System.out.println(id+"号员工删除");
        //模拟删除
        //employeeMapper.deleteEmployee(id);
        return 1;
    }

4.Caching组合注解
即可以定义cacheable又可以定义put还有evict
在这里插入图片描述
5.@CacheConfig统一配置相同的属性(标注在类上)
这样1CacheEvict、CachePut、Cacheable都不用写cacheNames 了

@CacheConfig(cacheNames = {"emp"})
@Service
public class EmployeeServiceImpl implements EmployeeService {

三.整合redis实现缓存(上面那些注解存储的数据就会存储到redi中)

  1. 引入spring-boot-starter-data-redis
  2. application.yml配置redis连接地址
  3. 使用RestTemplate操作redis
  4. redisTemplate.opsForValue();//操作字符串
  5. redisTemplate.opsForHash();//操作hash
  6. redisTemplate.opsForList();//操作list
  7. redisTemplate.opsForSet();//操作set
  8. redisTemplate.opsForZSet();//操作有序set
  9. 配置缓存、 CacheManagerCustomizers
  10. 测试使用缓存、 切换缓存、 CompositeCacheManager

3.1.Springboot自动加入了redisTemplate和对stringRedisTemplate的配置(两者操作都是一样的,只是stringRedisTemplate操作k-v都为String的,redisTemplate操作k-v为Object)

    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        RedisTemplate<Object, Object> template = new RedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(redisConnectionFactory);
        return template;
    }

3.2.若要保存对象,对象一定记得序列化(spring默认的对象序列化是通过JDK来序列化的,我们是看不懂的,所以需要切换为其他的序列化器)
3.3.springboot配置redis.
1.引入redis的start

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

2.yml配置.

spring:
  redis:
    host: 192.168.0.104
    port: 6379
    password:
    jedis:
      pool:
        max-active: 8
        max-wait: -1
        max-idle: 500
        min-idle: 0

3.自定义配置redis(这样存储对象通过存储json字符串的形式)

package com.wcy.springbootcache.config;

import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.cache.CacheManager;
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.*;

import java.net.UnknownHostException;
import java.time.Duration;

@Configuration
public class MyRedisConfig {
//    @Bean
//    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) throws UnknownHostException {
//        RedisTemplate<String, Object> template = new RedisTemplate();
//        template.setConnectionFactory(redisConnectionFactory);
//        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);
//        template.setDefaultSerializer(serializer);
//        return template;
//    }

    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);
        ObjectMapper objectMapper = new ObjectMapper();
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        serializer.setObjectMapper(objectMapper);

        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(serializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(serializer);
        redisTemplate.afterPropertiesSet();

        return redisTemplate;
    }

    /**
     * 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        //初始化一个RedisCacheWriter
        RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
        //设置CacheManager的值序列化方式为json序列化
        RedisSerializer<Object> jsonSerializer = new GenericJackson2JsonRedisSerializer();
        RedisSerializationContext.SerializationPair<Object> pair = RedisSerializationContext.SerializationPair
                .fromSerializer(jsonSerializer);
        RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig()
                .serializeValuesWith(pair);
        //设置默认超过期时间是30秒
        defaultCacheConfig.entryTtl(Duration.ofSeconds(30));
        //初始化RedisCacheManager
        return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
    }
}

4.测试缓存

    @Test
    void TestRedisTemplate(){
        Employee employee = employeeService.findEmployeeById(2);
        redisTemplate.opsForValue().set("k1",employee);
//        Employee k1 = (Employee)redisTemplate.opsForValue().get("k1");
//        System.out.println(k1);
    }

5.可使用@Cacheable、@CacheEvict、@CachePut,这样他会把数据缓存到redis中,1以前是存在ConconcaHashMap
例如:@Cacheable

@Service
public class DepatmentServiceImpl implements DepatmentService {
    @Autowired
    private DepatmentMapper depatmentMapper;
    @Cacheable(cacheNames = "dep",key = "#id")
    @Override
    public Department findDepa(Integer id) {
        System.out.println("查询了数据库");
        return depatmentMapper.findDepa(id);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值