卡飞资源网

专业编程技术资源共享平台

SpringBoot中使用缓存-1

在使用缓存前我们首先需要知道,为什么需要使用缓存。缓存能够给我带来什么解决什么问题。是否所有的数据都可以使用缓存。

1.缓存是什么?

缓存是一种存储数据的组件,它可以是硬件或软件,其目的是为了加快数据检索的速度,
减少对原始数据源的访问次数,从而提高整体性能和响应速度。缓存通常存储最近
或频繁访问的数据,这样当下次需要这些数据时,可以直接从缓存中快速获取,
而不必再次从较慢的源头(如硬盘、数据库或远程服务器)检索。从而提升软件的性能。向常见的有
浏览器缓存,CPU高速缓存,应用缓存,cdn缓存,数据库缓存等。

我们知道了缓存可以提高我们系统的访问速度,但是缓存也会带来一些问题。最常见的就是数据一致性问题,当然还有其他的问题。但是在利与弊的权衡下,牺牲一些小的问题(当然这个也要根据实际的常见和具体方案,并不能一概而论的说能否接收这些小的数据不一致问题)来提供系统的性能和延迟等问题,缓存还是有必要加入的。

下面注意接收下缓存在项目中的一些使用方式:

1.集成redis实现缓存

这个上一个章节写了一个简单登录模块介绍过,这次在重新介绍下

1. 在项目中引入依赖:

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

2.配置文件中配置相关的参数:

#redis配置
spring.data.redis.host=127.0.0.1
spring.data.redis.port=6379

3.配置redis的模板(当然你不配置也是可以的)

@Configuration
public class RedisConfig {
    @Bean("redisTemplate")
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<String, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setKeySerializer(keySerializer());
        redisTemplate.setHashKeySerializer(keySerializer());
        redisTemplate.setValueSerializer(valueSerializer());
        redisTemplate.setHashValueSerializer(valueSerializer());
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        return redisTemplate;
    }


    private RedisSerializer<String> keySerializer() {
        return new StringRedisSerializer();
    }

    private RedisSerializer<Object> valueSerializer() {
        //序列化所有类包括jdk提供的
        ObjectMapper objectMapper = new ObjectMapper();
        //设置序列化的域(属性,方法etc)以及修饰范围,Any包括private,public 默认是public的
        //ALL所有方位,ANY所有修饰符
        objectMapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        //enableDefaultTyping 原来的方法存在漏洞,2.0后改用如下配置
        //指定输入的类型
        objectMapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance,
                ObjectMapper.DefaultTyping.NON_FINAL);
        //如果java.time包下Json报错,添加如下两行代码
        objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
        objectMapper.registerModule(new JavaTimeModule());
        Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(objectMapper,Object.class);
        return serializer;
    }
}

3.使用测试


2.redis集成spring cache实现缓存

1.引入依赖:

在项目的pom.xml文件中添加Spring Boot的缓存启动器和Redis的依赖项

           <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-cache</artifactId>
        </dependency>
  1. 配置文件配置redis 参数(同上面的配置)


3.启用缓存
在Spring Boot的主类上使用
@EnableCaching注解来启用缓存支持


4.配置缓存管理器

@Configuration
public class CacheConfig {

    @Bean
    public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
        return new RedisCacheManager(
                RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory),
                //// 默认过期时间30分钟
                this.getRedisCacheConfigurationWithTtl(30),
                // 指定特定缓存的配置
                this.getRedisCacheConfigurationMap()
        );
    }

    private Map<String, RedisCacheConfiguration> getRedisCacheConfigurationMap() {
        // 在这里配置特定缓存的过期时间和序列化方式
        Map<String, RedisCacheConfiguration> redisCacheConfigurationMap = new HashMap<>();
        // 示例:为名为"myCache"的缓存设置60分钟的过期时间
        redisCacheConfigurationMap.put("myCache", this.getRedisCacheConfigurationWithTtl(60));
        return redisCacheConfigurationMap;
    }

    private RedisCacheConfiguration getRedisCacheConfigurationWithTtl(Integer minutes) {

        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);

        Jackson2JsonRedisSerializer<Object> jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer<>(om,Object.class);

        RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig();
        redisCacheConfiguration = redisCacheConfiguration.serializeValuesWith(
                RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer)
        ).prefixCacheNameWith("yulang-")
                .entryTtl(Duration.ofMinutes(minutes));

        return redisCacheConfiguration;
    }
}

5.使用注解方式使用

@Service
public class UserService {

    @Autowired
    private UserMapper userMapper;

  //获取缓存
    @Cacheable(value = "myCache", key = "#userId")
    public User findMyObjectById(String userId) {
        // 这里执行数据库查询或其他操作
        return userMapper.findById(userId);
    }

  // 添加缓存
    @CachePut(value = "myCache", key = "#myObject.userId")
    public User updateMyObject(User myObject) {
        // 更新对象的操作
        return userMapper.save(myObject);
    }

  // 删除缓存
    @CacheEvict(value = "myCache", key = "#userId")
    public void deleteMyObject(String userId) {
        // 删除对象的操作
        userMapper.deleteById(userId);
    }
}
    @Autowired
    private UserService userService;

    @PostMapping("/save")
    public void save() {
        User user = new User();
        user.setUserId("9999");
        user.setUserName("999");
        userService.updateMyObject(user);
    }


    @PostMapping("/get")
    public Object get() {
        return userService.findMyObjectById("9999");
    }

    @PostMapping("/delete")
    public void delete() {
        userService.deleteMyObject("9999");
    }

测试:

1.调用 /save 接口,缓存中会写入数据



2。调用 /get, 方法验证是否走缓存(观察是否走的查询)


  1. 删除 /delete,再次查询,缓存中没有数据,走的查询



总结两种的cache方式,都可以在实际的项目中使用。其实用哪一种都可以,关键点在于是否用的方便顺心。我们在实际的项目中其实两种结合起来使用过。在实际应用中,应根据具体的业务需求和系统特点来选择合适的集成方式。

第一种:编程式的方式在于灵活多变,可以更新实际的需求在不同的位置位置进行使用

优点

  1. 直接操作Redis:可以使用RedisTemplate直接操作Redis,执行各种Redis命令,灵活性更高。
  2. 性能较好:没有JCache API的额外开销,性能相对更好一些。

缺点

  1. 代码侵入性强:需要在业务代码中显式调用RedisTemplate,代码侵入性强,不易维护。
  2. 缺乏统一的缓存抽象:不同的缓存实现差异较大,不利于缓存的切换和统一管理

第二种: 申明式调用方式,在于使用简单方便,代码冗余度低,可以搭配其他的缓存框架使用。

优点

  1. 统一的缓存抽象:JCache(JSR-107)提供了一个统一的缓存管理接口,使得缓存的使用和切换变得更加灵活3。
  2. 注解支持:可以使用@Cacheable@CachePut@CacheEvict等注解来声明缓存逻辑,简化代码编写。
  3. 缓存抽象与实现分离:开发者可以专注于缓存的使用,而不需要关心具体的缓存实现,便于后期维护和升级。

缺点

  1. 性能开销:JCache API在使用时会有一些性能开销,因为它需要通过代理模式来拦截方法调用。
  2. 配置复杂:对于复杂的缓存配置,如自定义序列化方式、过期策略等,配置可能会比较繁琐
控制面板
您好,欢迎到访网站!
  查看权限
网站分类
最新留言