Spring Cache与Redis结合的使用方式

目录
  • Redis
  • 创建Spring项目
  • 集成Redis
  • Cache部分代码
    • @Cacheable 作用和配置方法
    • @CacheEvict 作用和配置方法

前不久做了一个需要查询多,更新少的功能,老司机同事建议用Redis来做缓存,同时结合Spring Cache来做,特来总结下。

Redis

Redis 是一个高性能key-value数据库,个人感觉就像java中的Map,不过比它更加强大。

由于我用的是Mac,下面介绍如何安装Redis。

brew update
brew install redis

开启服务

brew services start redis
brew services list

下面是我本机的运行截图

创建Spring项目

我这边为了简单方便,直接使用了Spring Boot,直接用IntelJ Idea,需要添加Redis、Cache和Lombok库。

集成Redis

集成Redis,直接在配置文件配置即可。

application.properties

#redis
spring.redis.host=localhost
spring.redis.port=6379
spring.redis.password=
spring.redis.timeout=0

然后测试下Redis是否集成功。

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class SpringcacheApplicationTests {
    @Autowired
    StringRedisTemplate redisTemplate;

    @Test
    public void contextLoads() {
        Assert.assertNotNull(redisTemplate);

        redisTemplate.opsForValue().set("hello", "world");
        String value = redisTemplate.opsForValue().get("hello");
        log.info("value = " + value);

        redisTemplate.delete("hello");
        value = redisTemplate.opsForValue().get("hello");
        log.info("value = " + value);
    }
}

运行结果如下,如果没有出错,则表示集成功。

2017-11-19 14:56:10.075 INFO 73896 --- [ main] c.m.s.SpringcacheApplicationTests : value = world
2017-11-19 14:56:10.076 INFO 73896 --- [ main] c.m.s.SpringcacheApplicationTests : value = null

Cache部分代码

配置CacheManager,它的实现部分是由RedisCacheManager来实现的,我们先设置缓存时间为3s,超过这个时间,缓存自动失效。

@Configuration
@EnableCaching
public class CachingConfig {

    @Bean
    public CacheManager cacheManager(RedisTemplate redisTemplate) {
        RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
        redisCacheManager.setDefaultExpiration(3);
        return redisCacheManager;
    }

    @Bean
    public CacheErrorHandler errorHandler() {
        return new RedisCacheErrorHandler();
    }

    @Slf4j
    private static class RedisCacheErrorHandler extends SimpleCacheErrorHandler {

        @Override
        public void handleCacheGetError(RuntimeException exception, Cache cache, Object key) {
            log.error("handleCacheGetError key = {}, value = {}", key, cache);
            log.error("cache get error", exception);
        }

        @Override
        public void handleCachePutError(RuntimeException exception, Cache cache, Object key, Object value) {
            log.error("handleCachePutError key = {}, value = {}", key, cache);
            log.error("cache put error", exception);
        }

        @Override
        public void handleCacheEvictError(RuntimeException exception, Cache cache, Object key) {
            log.error("handleCacheEvictError key = {}, value = {}", key, cache);
            log.error("cache evict error", exception);
        }

        @Override
        public void handleCacheClearError(RuntimeException exception, Cache cache) {
            log.error("handleCacheClearError value = {}", cache);
            log.error("cache clear error", exception);
        }
    }
}

添加一个简单的实体,然后添加服务接口和实现类。

@Data是lombok提供的,可以减少简洁代码。注意实体必须实现Serializable接口。

@Data
public class User implements Serializable {
    private int id;
    private String name;
    private String email;
}
public interface UserService {
    void addUser(User user);
    User findById(int id);
    void delete(int id);
}
@Slf4j
@Service
public class UserServiceImpl implements UserService {
    private final Map<Integer, User> db = new HashMap<>();
    @Override
    public void addUser(User user) {
        log.info("addUser.user = " + user);
        db.put(user.getId(), user);
    }

    @Cacheable(cacheNames = "user_cache", key = "#id")
    @Override
    public User findById(int id) {
        log.info("findById.id = " + id);
        return db.get(id);
    }

    @CacheEvict(cacheNames = "user_cache", key = "#id")
    @Override
    public void delete(int id) {
        log.info("delete.id = " + id);
        db.remove(id);
    }
}

上面Cacheable和CacheEvict就是Spring Cache提供的注解。具体说明如下。

@Cacheable 作用和配置方法

  • valuecacheNames

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如: @Cacheable(value=”mycache”) @Cacheable(value={”cache1”,”cache2”}

  • key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如: @Cacheable(value=”testcache”,key=”#userName”)

  • condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2”)

@CacheEvict 作用和配置方法

  • value

缓存的名称,在 spring 配置文件中定义,必须指定至少一个

例如: @CacheEvict(value=”my cache”)

  • key

缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合

例如: @CacheEvict(value=”testcache”,key=”#userName”)

  • condition

缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存

例如: @CacheEvict(value=”testcache”,condition=”#userName.length()>2”)

  • allEntries

是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存

例如: @CachEvict(value=”testcache”,allEntries=true)

  • beforeInvocation

是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存

例如: @CachEvict(value=”testcache”,beforeInvocation=true)

测试用例:

@Slf4j
@RunWith(SpringRunner.class)
@SpringBootTest
public class CacheTest {

    @Autowired
    UserService userService;

    @Test
    public void contextLoads() {
        Assert.assertNotNull(userService);

        // 创建一个实体
        User user = new User();
        user.setId(100);
        user.setName("admin");
        user.setEmail("admin@123.com");

        // 添加一个
        userService.addUser(user);

        // 根据Id查询
        log.info("user1 = " + userService.findById(100));
        sleep(1);
        // 等1s再次查询
        log.info("user2 = " + userService.findById(100));
        sleep(5);
        // 等5s再次查询
        log.info("user3 = " + userService.findById(100));

        // 添加一个
        userService.addUser(user);
        // 根据Id查询
        log.info("user4 = " + userService.findById(100));
        // 删除
        userService.delete(100);
        // 根据Id查询
        log.info("user5 = " + userService.findById(100));
    }

    private void sleep(int i) {
        try {
            Thread.sleep(i * 1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

测试结果

2017-11-19 15:08:35.732 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : addUser.user = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:35.921 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : findById.id = 100
2017-11-19 15:08:35.951 INFO 76558 --- [ main] cn.mycommons.springcache.CacheTest : user1 = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:37.016 INFO 76558 --- [ main] cn.mycommons.springcache.CacheTest : user2 = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:42.019 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : findById.id = 100
2017-11-19 15:08:42.021 INFO 76558 --- [ main] cn.mycommons.springcache.CacheTest : user3 = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:42.021 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : addUser.user = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:42.022 INFO 76558 --- [ main] cn.mycommons.springcache.CacheTest : user4 = User(id=100, name=admin, email=admin@123.com)
2017-11-19 15:08:42.023 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : delete.id = 100
2017-11-19 15:08:42.025 INFO 76558 --- [ main] c.m.s.service.impl.UserServiceImpl : findById.id = 100
2017-11-19 15:08:42.025 INFO 76558 --- [ main] cn.mycommons.springcache.CacheTest : user5 = null

从结果来看,添加一个数据后,第一次,查询是从UserServiceImpl中获取,再次查询,则没有直接调用UserServiceImpl,直接返回了缓存结果。

当超过缓存时间后,再次去查询,我们这边设置缓存时间为3s,等待5s后,再次查询,发现又从UserServiceImpl中获取数据。

当我们主动调用删除记录,同时同步清楚缓存数据后,发现查询是没有数据的。说明删除和清楚缓存操作实现了同步。

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • 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是Spring3.1引入的基于注解的缓存技术,本质上它并不是一个具体的缓存实现,而是一个对缓存使用的抽象,通过Spring AOP技术,在原有的代码上添加少量的注解来实现将这个方法转成缓存方法的效果. 本来想来个分析源码,奈何水平有限,先从实战搞起. 先引入依赖: <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-start

  • Spring @Cacheable redis异常不影响正常业务方案

    背景 项目中,使用@Cacheable进行数据缓存.发现:当redis宕机之后,@Cacheable注解的方法并未进行缓存冲突,而是直接抛出异常.而这样的异常会导致服务不可用. 原因分析 我们是通过@EnableCaching进行缓存启用的,因此可以先看@EnableCaching的相关注释 通过@EnableCaching的类注释可发现,spring cache的核心配置接口为:org.springframework.cache.annotation.CachingConfigurer /**

  • SpringBoot+SpringCache实现两级缓存(Redis+Caffeine)

    1. 缓存.两级缓存 1.1 内容说明 Spring cache:主要包含spring cache定义的接口方法说明和注解中的属性说明 springboot+spring cache:rediscache实现中的缺陷 caffeine简介 spring boot+spring cache实现两级缓存 使用缓存时的流程图 1.2 Sping Cache spring cache是spring-context包中提供的基于注解方式使用的缓存组件,定义了一些标准接口,通过实现这些接口,就可以通过在方法

  • 详解SpringBoot2.0的@Cacheable(Redis)缓存失效时间解决方案

    问题   @Cacheable注解不支持配置过期时间,所有需要通过配置CacheManneg来配置默认的过期时间和针对每个类或者是方法进行缓存失效时间配置. 解决   可以采用如下的配置信息来解决的设置失效时间问题 配置信息 @Bean public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) { return new RedisCacheManager( RedisCacheWriter.no

  • Spring Cache整合Redis实现方法详解

    导入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-cache</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>

  • Java SpringCache+Redis缓存数据详解

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

  • Spring Cache与Redis结合的使用方式

    目录 Redis 创建Spring项目 集成Redis Cache部分代码 @Cacheable 作用和配置方法 @CacheEvict 作用和配置方法 前不久做了一个需要查询多,更新少的功能,老司机同事建议用Redis来做缓存,同时结合Spring Cache来做,特来总结下. Redis Redis 是一个高性能key-value数据库,个人感觉就像java中的Map,不过比它更加强大. 由于我用的是Mac,下面介绍如何安装Redis. brew update brew install re

  • Spring Boot整合Spring Cache及Redis过程解析

    这篇文章主要介绍了Spring Boot整合Spring Cache及Redis过程解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 1.安装redis a.由于官方是没有Windows版的,所以我们需要下载微软开发的redis,网址: https://github.com/MicrosoftArchive/redis/releases b.解压后,在redis根目录打开cmd界面,输入:redis-server.exe redis.wind

  • 详解Spring Boot 访问Redis的三种方式

    目录 前言 开始准备 RedisTemplate JPA Repository Cache 总结 前言 最近在极客时间上面学习丁雪丰老师的<玩转 Spring 全家桶>,其中讲到访问Redis的方式,我专门把他们抽出来,在一起对比下,体验一下三种方式开发上面的不同, 分别是这三种方式 RedisTemplate JPA Repository Cache 开始准备 开始之前我们需要有Redis安装,我们采用本机Docker运行Redis, 主要命令如下 docker pull redis doc

  • Spring Cache和EhCache实现缓存管理方式

    目录 1.认识 Spring Cache 2.认识 EhCache 3.创建SpringBoot与MyBatis的整合项目 3.1 创建数据表 3.2 创建项目 4.配置EhCache缓存管理器 4.1 创建 ehcache.xml 配置文件 4.2 配置缓存管理器 4.3 开启缓存功能 5.使用EhCache实现缓存管理 5.1 创建实体类(Entity层) 5.2 数据库映射层(Mapper层) 5.3 业务逻辑层(Service层) 5.4 控制器方法(Controller层) 5.5 显

  • SpringBoot详解整合Spring Cache实现Redis缓存流程

    目录 1.简介 2.常用注解 2.1.@EnableCaching 2.2.@Cacheable 2.3.@CachePut 2.4.@CacheEvict 3.使用Redis当作缓存产品 3.1.坐标导入 3.2.yml配置 3.3.开启注解功能 3.4.使用@Cacheable 3.5.使用@CacheEvict 4.测试 1.简介 Spring Cache 是一个框架,实现了基于注解的缓存功能,只需要简单地加一个注解,就能实现缓存功能. Spring Cache 提供了一层抽象,底层可以切

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

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

  • 详解SpringBoot的三种缓存技术(Spring Cache、Layering Cache 框架、Alibaba JetCache 框架)

    引言 ​前两天在写一个实时数据处理的项目,项目要求是 1s 要处理掉 1k 的数据,这时候显然光靠查数据库是不行的,技术选型的时候老大跟我提了一下使用 Layering-Cache 这个开源项目来做缓存框架. ​之间问了一下身边的小伙伴,似乎对这块了解不多.一般也就用用 Redis 来缓存,应该是很少用多级缓存框架来专门性的管理缓存吧. ​趁着这个机会,我多了解了一些关于 SpringBoot 中缓存的相关技术,于是有了这篇文章! 在项目性能需求比较高时,就不能单单依赖数据库访问来获取数据了,必

  • 浅谈Spring Boot中Redis缓存还能这么用

    经过Spring Boot的整合封装与自动化配置,在Spring Boot中整合Redis已经变得非常容易了,开发者只需要引入Spring Data Redis依赖,然后简单配下redis的基本信息,系统就会提供一个RedisTemplate供开发者使用,但是今天松哥想和大伙聊的不是这种用法,而是结合Cache的用法.Spring3.1中开始引入了令人激动的Cache,在Spring Boot中,可以非常方便的使用Redis来作为Cache的实现,进而实现数据的缓存. 工程创建 首先创建一个Sp

随机推荐