SpringBoot缓存注解学习笔记之Redis

之前用SpringBoot+MyBatisPlus+SpringMVC整合搭建了一个基础web开发框架,使用这三个框架搭建出来项目结构非常的清爽,没有过多的配置文件,各个模块之间有清晰的联系,非常适合敏捷开发。

最近学习了Redis这个基于内存的,Key-Value数据形式的高性能数据库,感觉学习了入门之后很简单,没有体会到它具体能干嘛,我就想着使用Redis这个数据库来整合之前搭建的框架,利用Spring中的缓存机制,将查询的信息缓存到Redis中。

、、、、、、、、、、、、
个人博客地址:http://z77z.oschina.io/
,,,,,,,,,,,,

安装Redis

Window 下安装 下载地址:https://github.com/MSOpenTech/redis/releases。 Redis 支持32 位和64 位。这个需要根据你系统平台的实际情况选择,这里我们下载 Redis-x64-xxx.zip压缩包到 C盘的tools目录中,解压后,将文件夹重新命名为 redis。

下载Redis版本

打开一个 cmd 窗口 使用cd命令切换目录到 C:\tools\redis 运行 redis-server.exe redis.windows.conf 。
如果想方便的话,可以把 redis 的路径加到系统的环境变量里,这样就省得再输路径了,后面的那个 redis.windows.conf 可以省略,如果省略,会启用默认的。输入之后,会显示如下界面:

启动成功后

启动成功后不要关闭命令窗口,不然redis服务也会关闭。如果不想每次使用都一直开着这个命令窗口,可以将redis服务添加到windows的服务中:

安装命令:
redis-server.exe --service-install redis.windows.conf --loglevel verbose 

卸载命令:
redis-server --service-uninstall

安装成功后,可以在windows的服务管理中对redis进行管理,就不用每次都打开命令窗口来启动redis服务了,如下图:

在windows中管理redis服务

获取之前项目

环境我就直接在之前的整合框架上进行搭建,之前项目下载地址:https://git.oschina.net/z77z/springboot_mybatisplus
注意:之前搭建这个框架的时候我为了获取基础数据,在启动springboot的时候也启动了爬虫程序,如果不想每次启动都启动爬虫可以注释掉启动类中的run方法。

添加Redis依赖到pom.xml中

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

在application.properties中添加配置

# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
spring.redis.password=
# 连接池最大连接数(使用负值表示没有限制)
spring.redis.pool.max-active=8
# 连接池最大阻塞等待时间(使用负值表示没有限制)
spring.redis.pool.max-wait=-1
# 连接池中的最大空闲连接
spring.redis.pool.max-idle=8
# 连接池中的最小空闲连接
spring.redis.pool.min-idle=0
# 连接超时时间(毫秒)
spring.redis.timeout=0

我们需要做的配置到这里就已经完成了,Spring Boot会在侦测到存在Redis的依赖并且Redis的配置是可用的情况下,使用RedisCacheManager初始化CacheManager。也就是说要使用缓存的话,SpringBoot就会选择Redis来作为缓存的容器。

编写一个简单的redis读写测试列

/**
 * redis读写测试
 * @author z77z
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    
    @Test
    public void redisTest() throws Exception {

        //保存字符串
        stringRedisTemplate.opsForValue().set("aaa", "111");
        //读取字符串
        String aaa = stringRedisTemplate.opsForValue().get("aaa");
        System.out.println(aaa);
    }
}

打印结果:

redis读写测试结果

编写缓存测试列

不使用缓存:

/**
 * 获取数据,并且做缓存处理
 * @author z77z
 *
 */
@Component
public class RedisCache {
    
    @Autowired
    BeautifulPicturesService beautifulPicturesService;
    //@Cacheable(value = "BeautifulPictures")
    public BeautifulPictures getBeautifulPicturesList(String id) {
        return beautifulPicturesService.selectById(id);
    }
}

/**
 * 测试类
 * @author z77z
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
    @Autowired
    BeautifulPicturesService beautifulPicturesService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    RedisCache redisCache;
    
    @Test
    public void redisTest() throws Exception {

        //保存字符串
        stringRedisTemplate.opsForValue().set("aaa", "111");
        //读取字符串
        String aaa = stringRedisTemplate.opsForValue().get("aaa");
        System.out.println(aaa);
    }
    
    @Test
    public void CacheTest() {
        BeautifulPictures beautifulPicture = redisCache.getBeautifulPicturesList("1011");
        System.out.println("第一次查询结果:");
        System.out.println(beautifulPicture);

        BeautifulPictures beautifulPicture1 = redisCache.getBeautifulPicturesList("1011");
        System.out.println("第二次查询结果:");
        System.out.println(beautifulPicture1);
    }
}

执行结果:

不使用缓存测试结果

可以从日志中看出两次查询都是执行了sql,也就是执行了getBeautifulPicturesList这个方法

使用缓存:

在getBeautifulPicturesList方法的上面添加@Cacheable(value = "BeautifulPictures")注解,当请求这个方法时会先判断缓存中是否存在,存在就在缓存中获取,不会执行这个方法。不存在就正常执行这个方法获取返回值并且存如缓存中。添加注解后执行结果如下:

添加缓存注释后

从日志中可以看出,第一次查询的时候执行的sql,而第二次查询的时候没有执行sql,说明是从缓存中获取的数据。

缓存数据一致性保证

CRUD (Create 创建,Retrieve 读取,Update 更新,Delete 删除) 操作中,除了 R具备幂等性,其他三个发生的时候都可能会造成缓存结果和数据库不一致。为了保证缓存数据的一致性,在进行 CUD 操作的时候我们需要对可能影响到的缓存进行更新或者清除。如下:

/**
 * 获取数据,并且做缓存处理
 * @author z77z
 *
 */
@Component
public class RedisCache {
    
    @Autowired
    BeautifulPicturesService beautifulPicturesService;
    
    //查询
    @Cacheable(value = "beautifulPictures")
    public BeautifulPictures getBeautifulPicturesList(String id) {
        return beautifulPicturesService.selectById(id);
    }
    
    //修改
    @CachePut(value = "beautifulPictures")
    public void updateBeautifulPicture(String id) {
        BeautifulPictures beautifulPictures = new BeautifulPictures();
        beautifulPictures.setTitle("Title被我修改了一下,哈哈");
        beautifulPictures.setId(id);
        beautifulPicturesService.updateById(beautifulPictures);
    }
}
/**
 * 测试类
 * @author z77z
 *
 */
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class RedisCacheTest {
    @Autowired
    BeautifulPicturesService beautifulPicturesService;

    @Autowired
    StringRedisTemplate stringRedisTemplate;
    
    @Autowired
    RedisCache redisCache;
    
    @Test
    public void redisTest() throws Exception {

        //保存字符串
        stringRedisTemplate.opsForValue().set("aaa", "111");
        //读取字符串
        String aaa = stringRedisTemplate.opsForValue().get("aaa");
        System.out.println(aaa);
    }
    
    @Test
    public void CacheTest() {
        String id = "1";
        BeautifulPictures beautifulPicture = redisCache.getBeautifulPicturesList(id);
        System.out.println("第一次查询结果:");
        System.out.println(beautifulPicture);

        BeautifulPictures beautifulPicture1 = redisCache.getBeautifulPicturesList(id);
        System.out.println("第二次查询结果:");
        System.out.println(beautifulPicture1);
        
        redisCache.updateBeautifulPicture(id);
        
        BeautifulPictures beautifulPicture2 = redisCache.getBeautifulPicturesList(id);
        System.out.println("第三次查询结果:");
        System.out.println(beautifulPicture2);
    }
}

保持缓存一致性测试结果:

保持缓存的一致性测试

在会导致数据发生改变的方法上添加@CachePut(value = "beautifulPictures")注解,添加后会更新缓存中的值,并且每次都会正常执行方法内容。

SpringBoot缓存注解详解

  • @Cacheable:作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存

主要参数说明:

  1. value:缓存的名称,在 spring 配置文件中定义,必须指定至少一个,例如:@Cacheable(value=”mycache”) 或者 @Cacheable(value={”cache1”,”cache2”}。
  2. key:缓存的 key,可以为空,如果指定要按照 SpEL 表达式编写,如果不指定,则缺省按照方法的所有参数进行组合,例如:@Cacheable(value=”testcache”,key=”#userName”)。
  3. condition:缓存的条件,可以为空,使用 SpEL 编写,返回 true 或者 false,只有为 true 才进行缓存,例如:@Cacheable(value=”testcache”,condition=”#userName.length()>2。
  • @CachePut:作用是主要针对方法配置,能够根据方法的请求参数对其结果进行缓存,和 @Cacheable 不同的是,它每次都会触发真实方法的调用

主要参数说明:

  1. valuekeycondition参数配置和@Cacheable一样。
  • @CacheEvict:作用是主要针对方法配置,能够根据一定的条件对缓存进行清空

主要参数说明:

  1. valuekeycondition参数配置和@Cacheable一样。
  2. allEntries:是否清空所有缓存内容,缺省为 false,如果指定为 true,则方法调用后将立即清空所有缓存,例如:@CachEvict(value=”testcache”,allEntries=true)。
  3. beforeInvocation:是否在方法执行前就清空,缺省为 false,如果指定为 true,则在方法还没有执行的时候就清空缓存,缺省情况下,如果方法执行抛出异常,则不会清空缓存,例如@CachEvict(value=”testcache”,beforeInvocation=true)。

另外说下: @cache(“something");这个相当于save()操作,@cachePut相当于Update()操作,只要他标示的方法被调用,那么都会缓存起来,而@cache则是先看下有没已经缓存了,然后再选择是否执行方法。@CacheEvict相当于Delete()操作。用来清除缓存用的。

荆轲刺秦王~

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,362评论 5 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,330评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,247评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,560评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,580评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,569评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,929评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,587评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,840评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,596评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,678评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,366评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,945评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,929评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,165评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,271评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,403评论 2 342

推荐阅读更多精彩内容