Spring Cache+Redis缓存数据的实现示例

目录
  • 1、为什么使用缓存
  • 2、常用的缓存注解
    • 2.1 @Cacheable
    • 2.2 @CacheEvict
    • 2.3、@Cacheput
    • 2.4、@Caching
    • 2.5、@CacheConfig
  • 3、SpringBoot缓存支持
  • 4、项目继承Spring Cache+Redis
    • 4.1 添加依赖
    • 4.2 配置类
    • 4.3 添加redis配置
    • 4.4 接口中使用缓存注解
    • 4.5 缓存效果测试

1、为什么使用缓存

  我们知道内存的读取速度远大于硬盘的读取速度。当需要重复地获取相同数据时,一次一次地请求数据库或者远程服务,导致在数据库查询或远程方法调用上消耗大量的时间,最终导致程序性能降低,这就是数据缓存要解决的问题。

  Spring Cache 是一个非常优秀的缓存组件。自Spring 3.1起,提供了类似于@Transactional注解事务的注解Cache支持,且提供了Cache抽象,方便切换各种底层Cache(如:redis)

  使用Spring Cache的好处

1,提供基本的Cache抽象,方便切换各种底层Cache;

2,通过注解Cache可以实现类似于事务一样,缓存逻辑透明的应用到我们的业务代码上,且只需要更少的代码就可以完成;

3,提供事务回滚时也自动回滚缓存;

4,支持比较复杂的缓存逻辑;

  一旦配置好Spring缓存支持,就可以在Spring容器里管理的Bean中使用缓存注解(基于AOP原理),一般情况下,都是在业务层(Service类)使用这些注解。

2、常用的缓存注解

2.1 @Cacheable

  @Cacheable可以标记在一个方法上,也可以标记在一个类上。当标记在一个方法上时表示该方法是支持缓存的;当标记在一个类上时则表示该类所有的方法都是支持缓存的。对于一个支持缓存的方法,在方法执行前,Spring先检查缓存中是否存在该方法返回的数据,如果存在,则直接返回缓存数据;如果不存在,则调用方法并将方法返回值写入缓存

  @Cacheable注解经常使用value、key、condition等属性

value:缓存的名称,指定一个或多个缓存名称。如

@Cacheable(value="mycache")或者@Cacheable(value={<!--{cke_protected}{C}%3C!%2D%2D%20%2D%2D%3E-->"cache1","cache2"})

该属性与cacheNames属性意义相同

key:缓存的key,可以为空。如果指定。需要按照SpEL编写;如果不指定,则默认按照方法的所有参数进行组合。如

@Cacheable(value="testcache",key="#student.id")

condition:缓存的条件,可以为空,如果指定,需要按照SpEL编写,返回true或者false,只有为true才进行缓存。如

@Cacheable(value="testcache",condition="#student.id>2")

该属性与unless相反,条件成立时,不进行缓存

2.2 @CacheEvict

一般用在更新或者删除方法上

  @CacheEvict是用来标注在需要清除 缓存元素的方法或类上的。当标记在一个类上时,表示其中所有方法的执行都会触发缓存的清除操作。@CacheEvict可以指定的属性有value、key、conditon、allEntries和beforeInvocation。其中,value、key和condition的语义与@Cacheable对应的属性类似。

allEntries:是否清空所有缓存内容,默认为false,如果指定为true,则方法调用后将立即清空所有缓存。如

@CacheEvict(value="testcache",allEntries=true)

beforeInvocation:是否在方法执行前就清空,默认为false,如果指定为true,则在方法还没有执行时就清空缓存。默认情况下,如果方法执行抛出异常,则不会清空缓存。

2.3、@Cacheput

  使用该注解标志的方法,每次都会执行,并将结果存入指定的缓存中。其他方法可以直接从响应的缓存中读取缓存数据,而不需要再去查询数据库。一般用在新增方法上

2.4、@Caching

  该注解可以在一个方法或类上同时指定多个Spring Cache相关的注解。其拥有三个属性:cacheable、put和evict,分别用于指定@Cacheable、@CachePut和@CacheEvict。示例代码如下:

@Caching(
cacheable=@Cacheable("cache1"),
evict={@CacheEvict("cache2"),@CacheEvict(value="cache3",allEntries=true)}
)

2.5、@CacheConfig

  所有的Cache注解都需要提供Cache名称,如果每个Service方法上都包含相同的Cache名称,可能写起来重复。此时可以使用@CacheConfig注解作用在类上,设置当前缓存的一些公共配置。

3、SpringBoot缓存支持

  在SpringBoot应用中,使用缓存技术只需在应用中引入相关缓存技术的依赖,并在配置类中使用@EnableCaching注解开启缓存支持即可。

4、项目继承Spring Cache+Redis

4.1 添加依赖

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

        <!-- spring2.X集成redis所需common-pool2-->
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-pool2</artifactId>
            <version>2.6.0</version>
        </dependency>

4.2 配置类

/**
 * Redis+Cache配置类
 */
@Configuration
@EnableCaching
public class RedisConfig {
    /**
     * 自定义key规则
     * @return
     */
    @Bean
    public KeyGenerator keyGenerator() {
        return new KeyGenerator() {
            @Override
            public Object generate(Object target, Method method, Object... params) {
                StringBuilder sb = new StringBuilder();
                sb.append(target.getClass().getName());
                sb.append(method.getName());
                for (Object obj : params) {
                    sb.append(obj.toString());
                }
                return sb.toString();
            }
        };
    }

    /**
     * 设置RedisTemplate规则
     * @param redisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) {
        RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(redisConnectionFactory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        // 指定要序列化的域,field,get和set,以及修饰符范围,ANY是都有包括private和public
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        // 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会跑出异常
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        //序列号key value
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(jackson2JsonRedisSerializer);
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashValueSerializer(jackson2JsonRedisSerializer);

        redisTemplate.afterPropertiesSet();
        return redisTemplate;
    }

    /**
     * 设置CacheManager缓存规则
     * @param factory
     * @return
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory factory) {
        RedisSerializer<String> redisSerializer = new StringRedisSerializer();
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);

        //解决查询缓存转换异常的问题
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);

        // 配置序列化(解决乱码的问题),过期时间600秒
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(600))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(redisSerializer))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer))
                .disableCachingNullValues();

        RedisCacheManager cacheManager = RedisCacheManager.builder(factory)
                .cacheDefaults(config)
                .build();
        return cacheManager;
    }

}

4.3 添加redis配置

# redis配置
spring.redis.host=192.168.159.33
spring.redis.port=6379
spring.redis.database= 0
spring.redis.timeout=1800000

spring.redis.lettuce.pool.max-active=20
spring.redis.lettuce.pool.max-wait=-1
#最大阻塞等待时间(负数表示没限制)
spring.redis.lettuce.pool.max-idle=5
spring.redis.lettuce.pool.min-idle=0

4.4 接口中使用缓存注解

Service实现类中添加相应的注解

@Service
public class DictServiceImpl extends ServiceImpl<DictMapper, Dict> implements DictService {

    //根据上级id查询子数据列表
    @Override
    @Cacheable(value = "dict",keyGenerator = "keyGenerator")
    public List<Dict> findChildData(Long id) {
        QueryWrapper<Dict> wrapper=new QueryWrapper<>();
        wrapper.eq("parent_id",id);
        List<Dict> list = baseMapper.selectList(wrapper);
        //向list集合中的每个dict对象中设置hasChildren
        list.forEach(x->{
            Long dictId = x.getId();
            boolean isChild = this.isChildren(dictId);
            x.setHasChildren(isChild);
        });
        return list;
    }

    //导出数据字典接口
    @Override
    public void exportDictData(HttpServletResponse response) {
        //设置下载信息
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
        String fileName = "dict";
        response.setHeader("Content-disposition", "attachment;filename="+ fileName + ".xlsx");

        //查询数据库
        List<Dict> dictList = baseMapper.selectList(null);
        //Dict-->DictEeVo
        List<DictEeVo> dictEeVoList=new ArrayList<>();
        dictList.forEach(x->{
            DictEeVo dictEeVo=new DictEeVo();
            BeanUtils.copyProperties(x,dictEeVo);
            dictEeVoList.add(dictEeVo);
        });

        try {
            //调用方法实现写操作
            EasyExcel.write(response.getOutputStream(), DictEeVo.class)
                    .sheet("dict")
                    .doWrite(dictEeVoList);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    //导入数据字典
    @Override
    @CacheEvict(value = "dict", allEntries=true)
    public void importDictData(MultipartFile file) {
        try {
            //excel数据取出来并添加到数据库中
            EasyExcel.read(file.getInputStream(),DictEeVo.class,new DictListener(baseMapper))
            .sheet()
            .doRead();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    //判断id下面是否有子数据
    private boolean isChildren(Long id){
        QueryWrapper<Dict> wrapper=new QueryWrapper<>();
        wrapper.eq("parent_id",id);
        Integer count = baseMapper.selectCount(wrapper);
        return count > 0;
    }
}

4.5 缓存效果测试

我们现在调用根据上级id查询子数据列表这个方法的controller

第一次访问接口

查看控制台:

查看redis中是否有缓存的数据

用连接工具查看下redis中的数据,方便数据的可视化

从上面的数据不难发现,数据已经被缓存到了redis中

清空SpringBoot的控制台,再次发起相同的请求,看是否会再次请求数据库

第二次请求的控制台输出如下:

页面中的数据也正常获取到了,如下:

  从上面的效果可以很明显的看到,我们第一次请求后端接口的时候,由于缓存中并没有需要的数据,所以会被缓存到redis中,第二次请求相同接口的时候,Spring先检查缓存中是否存在该方法返回的数据,如果存在,则直接返回缓存数据,减小对数据库查询的压力。上面的缓存一定要设置下TTL,这样长期不用的数据就会自动失效

到此这篇关于Spring Cache+Redis缓存数据的实现示例的文章就介绍到这了,更多相关Spring Cache Redis缓存 内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • 浅谈SpringCache与redis集成实现缓存解决方案

    缓存可以说是加速服务响应速度的一种非常有效并且简单的方式.在缓存领域,有很多知名的框架,如EhCache .Guava.HazelCast等.Redis作为key-value型数据库,由于他的这一特性,Redis也成为一种流行的数据缓存工具. 在传统方式下对于缓存的处理代码是非常臃肿的. 例如:我们要把一个查询函数加入缓存功能,大致需要三步. 一.在函数执行前,我们需要先检查缓存中是否存在数据,如果存在则返回缓存数据 二.如果不存在,就需要在数据库的数据查询出来. 三.最后把数据存放在缓存中,当

  • SpringCache 分布式缓存的实现方法(规避redis解锁的问题)

    简介 spring 从3.1 开始定义 org.springframework.cache.Cache org.springframework.cache.CacheManager 来统一不同的缓存技术 并支持使用JCache(JSR-107)注解简化我们的开发 基础概念 实战使用 整合SpringCache简化缓存开发 常用注解 常用注解 说明 @CacheEvict 触发将数据从缓存删除的操作 (失效模式) @CachePut 不影响方法执行更新缓存 @Caching 组合以上多个操作 @C

  • Spring Cache手动清理Redis缓存

    这篇文章主要介绍了Spring Cache手动清理Redis缓存,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 注册cacheRedisTemplate 将 cache 的 RedisTemplate 注册为Bean @Bean(name = "cacheRedisTemplate") public RedisTemplate cacheRedisTemplate(@Qualifier("jedisConnectionFac

  • Java SpringCache+Redis缓存数据详解

    目录 前言 一.什么是SpringCache 二.项目集成Spring Cache + Redis 1.配置方式 三.使用Spring Cache 四.SpringCache原理与不足 1.读模式 2.写模式:(缓存与数据库一致) 五.总结 前言 这几天学习谷粒商城又再次的回顾了一次SpringCache,之前在学习谷粒学院的时候其实已经学习了一次了!!! 这里就对自己学过来的内容进行一次的总结和归纳!!! 一.什么是SpringCache Spring Cache 是一个非常优秀的缓存组件.自

  • 使用SpringCache加Redis做缓存

    目录 Redis + SpringCache 1. 添加依赖 <!-- redis --><dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId></dependency><!-- spring2.X集成redis所需common-pool2-->

  • 配置Spring4.0注解Cache+Redis缓存的用法

    前言: 目前公司项目在上一个技术架构的处理,已经搭建好了Redis,但redis只用在了做session的管理,然而 后台的对象缓存没有用上 1. redis 和 ehcache的区别: 简单了解了下,个人觉得 从部署上而言,redis更适合分布式部署,ehcache是在每台应用服务器上开辟一块内存做缓存,集群时还得考虑缓存的情况, redis就不需要考虑缓存了.单独部署在一台服务器中(也可以是在某一台应用服务器中) 2. 项目配置(spring mvc+maven+mybaits+redis)

  • spring boot+spring cache实现两级缓存(redis+caffeine)

    spring boot中集成了spring cache,并有多种缓存方式的实现,如:Redis.Caffeine.JCache.EhCache等等.但如果只用一种缓存,要么会有较大的网络消耗(如Redis),要么就是内存占用太大(如Caffeine这种应用内存缓存).在很多场景下,可以结合起来实现一.二级缓存的方式,能够很大程度提高应用的处理效率. 内容说明: 缓存.两级缓存 spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 spring boot

  • Spring Cache+Redis缓存数据的实现示例

    目录 1.为什么使用缓存 2.常用的缓存注解 2.1 @Cacheable 2.2 @CacheEvict 2.3.@Cacheput 2.4.@Caching 2.5.@CacheConfig 3.SpringBoot缓存支持 4.项目继承Spring Cache+Redis 4.1 添加依赖 4.2 配置类 4.3 添加redis配置 4.4 接口中使用缓存注解 4.5 缓存效果测试 1.为什么使用缓存   我们知道内存的读取速度远大于硬盘的读取速度.当需要重复地获取相同数据时,一次一次地请

  • Spring项目中使用Cache Redis实现数据缓存

    目录 Spring项目中实现数据缓存 一.Spring Cache + Redis 介绍 二.项目中集成 1. 引入依赖 2. 添加 redis 配置类 3. 配置文件增加 redis 配置 4. 启动安装好的 redis 三.Spring Cache 常用注解介绍 1. @Cacheable 2. @CachePut 3. @CacheEvict 四.功能里实现缓存操作 查询操作 导入操作 Spring项目中实现数据缓存 有时候我们为了提高查询速度,会使用缓存,但是并不是所有数据都适合放到缓存

  • spring整合redis实现数据缓存的实例代码

    数据缓存原因:有些数据比较多,如果每次访问都要进行查询,无疑给数据库带来太大的负担,将一些庞大的查询数据并且更新次数较少的数据存入redis,能为系统的性能带来良好的提升. 业务逻辑思路:登入系统,访问数据时,检查redis是否有缓存,有则直接从redis中提取,没有则从数据库查询出,并存入redis中做缓存. 为什么要用redis做缓存: (1)异常快速:Redis的速度非常快,每秒能执行约11万集合,每秒约81000+条记录. (2)支持丰富的数据类型:Redis支持最大多数开发人员已经知道

  • 基于 Spring Aop 环绕通知实现 Redis 缓存双删功能(示例代码)

    基于 spring aop 常规应用场景多是用于日志记录以及实现 redis 分布式锁,在 github 中也有项目是把它拿来当作缓存的异常捕捉.从而避免影响实际业务的开发:在某天,笔者有个业务开发是给某个服务模块增加 redis 缓存.增加缓存就会涉及 redis 删除.所以笔者就在思考是不是可以用环绕通知的方式来进行实现 代码实现 结构示意图: 自定义注解 RedisDelByDbUpdate @Repeatable 表示允许在同一个地方上使用相同的注解,没有该注解时贴相同注解会报错 @Ta

  • SpringBoot Redis缓存数据实现解析

    这篇文章主要介绍了SpringBoot Redis缓存数据实现解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.启用对缓存的支持 spring对缓存的支持有两种方式: a.注解驱动的缓存 b.XML声明的缓存 本文主要介绍纯Java配置的缓存,那么必须在配置类上添加@EnableCaching,这样的话就能启动注解驱动的缓存. 2.使用Redis缓存 缓存的条目不过是一个键值对(Key-Value),其中key描述了产生value的操作和

  • 使用Spring Cache设置缓存条件操作

    目录 Spring Cache设置缓存条件 原理 @Cacheable的常用属性及说明 Root对象 @CachePut的常用属性同@Cacheable Cache缓存配置 1.pom.xml 2.Ehcache配置文件 3.配置类 4.示例 Spring Cache设置缓存条件 原理 从Spring3.1开始,Spring框架提供了对Cache的支持,提供了一个对缓存使用的抽象,通过在既有代码中添加少量它定义的各种 annotation,即能够达到缓存方法的返回对象的作用. 提供的主要注解有@

  • 使用Spring Data Redis实现数据缓存的方法

    引言 目前很多系统为了解决数据读写的性能瓶颈,在系统架构设计中使用Redis实现缓存,Spring框架为了让开发人员更加方便快捷的使用Redis实现缓存,对Redis的操作进行了包装. 0.缓存 个人理解的缓存是指用于存储频繁使用的数据的空间,关注点是存储数据的空间和使用频繁的数据.缓存技术,简单的说就是先从缓存中查询数据是否存在,存在则直接返回,不存在再执行相应的操作获取数据,并将获取的数据存储到缓存中,它是一种提升系统性能的重要方法. 1.Redis Redis是一个开源的.内存存储key-

  • spring整合redis缓存并以注解(@Cacheable、@CachePut、@CacheEvict)形式使用

    maven项目中在pom.xml中依赖2个jar包,其他的spring的jar包省略: <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.1</version> </dependency> <dependency> <groupId>org.springfra

随机推荐