春节就要到了,在回家之前要赶快把今年欠下的技术债还清。so,今天继续。Spring Boot前面已经预热了n篇博客了,今天我们来继续看如何在Spring Boot中解决数据缓存问题。本篇博客是以初识在Spring Boot中使用JPA为基础的,先了解如何实现数据访问,然后才好实现数据缓存。OK,对于Spring Boot尚有疑问的小伙伴可以先移步这里从SpringMVC到Spring Boot,老司机请略过。

OK,废话不多说,开始今天的技术之旅吧。

在实际开发中,对于要反复读写的数据,最好的处理方式是将之在内存中缓存一份,频繁的数据库访问会造成程序效率低下,同时内存的读写速度本身就要强于硬盘。Spring在这一方面给我们提供了诸多的处理手段,而Spring Boot又将这些处理方式进一步简化,接下来我们就来看看如何在Spring Boot中解决数据缓存问题。


创建Project并添加数据库驱动

Spring Boot的创建方式还是和我们前文提到的创建方式一样,不同的是这里选择添加的依赖不同,这里我们添加Web、Cache和JPA依赖,如下图:



创建成功之后,接下来添加数据库驱动,我还是使用MySql,在pom.xml中添加数据库驱动,如下:

<dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

配置application.properties

这个application.properties的配置还是和初识在Spring Boot中使用JPA一样,各个参数的含义我这里也不再赘述,我们直接来看代码:

spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/sang?useUnicode=true&characterEncoding=utf-8
spring.datasource.username=root
spring.datasource.password=sang

spring.jpa.hibernate.ddl-auto=update
spring.jpa.show-sql=true
spring.jackson.serialization.indent_output=true

创建实体类

@Entity
public class Person {
    @Id
    @GeneratedValue
    private Long id;
    private String name;
    private String address;
    private Integer age;

    public Person() {
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public Person(Long id, String name, String address, Integer age) {
        this.id = id;
        this.name = name;
        this.address = address;
        this.age = age;
    }
}

创建实体类的Repository

public interface PersonRepository extends JpaRepository<Person,Long> {
}

创建业务类

业务接口

public interface DemoService {
    public Person save(Person person);

    public void remove(Long id);

    public Person findOne(Person person);
}

实现类

@Service
public class DemoServiceImpl implements DemoService {
    @Autowired
    PersonRepository personRepository;

    @CachePut(value = "people", key = "#person.id")
    @Override
    public Person save(Person person) {
        Person p = personRepository.save(person);
        System.out.println("为id、key为" + p.getId() + "数据做了缓存");
        return p;
    }

    @CacheEvict(value = "people")
    @Override
    public void remove(Long id) {
        System.out.println("删除了id、key为" + id + "的数据缓存");
        personRepository.delete(id);
    }

    @Cacheable(value = "people", key = "#person.id")
    @Override
    public Person findOne(Person person) {
        Person p = personRepository.findOne(person.getId());
        System.out.println("为id、key为" + p.getId() + "数据做了缓存");
        return p;
    }
}@Service
public class DemoServiceImpl implements DemoService {
    @Autowired
    PersonRepository personRepository;

    @CachePut(value = "people", key = "#person.id")
    @Override
    public Person save(Person person) {
        Person p = personRepository.save(person);
        System.out.println("为id、key为" + p.getId() + "数据做了缓存");
        return p;
    }

    @CacheEvict(value = "people")
    @Override
    public void remove(Long id) {
        System.out.println("删除了id、key为" + id + "的数据缓存");
        personRepository.delete(id);
    }

    @Cacheable(value = "people", key = "#person.id")
    @Override
    public Person findOne(Person person) {
        Person p = personRepository.findOne(person.getId());
        System.out.println("为id、key为" + p.getId() + "数据做了缓存");
        return p;
    }
}

关于这个实现类我说如下几点:

1.@CachePut表示缓存新添加的数据或者更新的数据到缓存中,两个参数value表示缓存的名称为people,key表示缓存的key为person的id

2.@CacheEvict表示从缓存people中删除key为id的数据

3.@Cacheable表示添加数据到缓存中,缓存名称为people,缓存key为person的id属性。


创建Controller

@RestController
public class CacheController {
    @Autowired
    DemoService demoService;

    @RequestMapping("/put")
    public Person put(Person person) {
        return demoService.save(person);
    }

    @RequestMapping("/able")
    public Person cacheable(Person person) {
        return demoService.findOne(person);
    }

    @RequestMapping("/evit")
    public String evit(Long id) {
        demoService.remove(id);
        return "ok";
    }
}

OK ,做完这一切我们就可以来测试我们刚刚写的缓存了。

测试

看我们的Controller,我们有三个地址要测试,一个一个来。当然,在 测试之前,我们先来看看初始状态下的数据库是什么样子的:


首先我们在浏览器中访问http://localhost:8080/able?id=1,得到如下访问结果:



这个时候查看控制台,输出内容如下:



说是数据已经被缓存了,这个时候我们再继续在浏览器中刷新继续请求id为1的数据,会发现控制台不会继续打印日志出来,就是因为数据已被存于缓存之中了。


接下来我们向浏览器中输入http://localhost:8080/put?age=47&name=奥巴牛&address=米国,访问结果如下:



这个时候查看控制台打印的日志如下:



再查看数据表,数据已插入成功:



此时,我们在浏览器中输入http://localhost:8080/able?id=106,访问刚刚插入的这条数据,结果如下:



这个时候查看控制台,发现并没有数据数据,就是因为数据已经处于缓存中了。


最后我们在浏览器中输入http://localhost:8080/evit?id=106,将数据从缓存中移除,访问结果如下:



这个时候查看控制台,已经提示缓存移除掉了:



同时数据也从数据库删除掉了,这个时候如果还需要该数据则需要我们继续向表中添加数据。

缓存技术切换

Spring Boot默认情况下使用ConcurrentMapCacheManager作为缓存技术,有的时候你可能想替换为其他的缓存方式,在Spring Boot中进行缓存的切换非常简单,我这里以Google提供的Guava为例,如果要使用这种缓存策略,只需要添加相应的依赖即可,如下:

<dependency>
    <groupId>com.google.guava</groupId>
    <artifactId>guava</artifactId>
    <version>20.0</version>
</dependency>

就这样就可以了。实际上在Spring Boot中,底层使用哪一种缓存我们并不必做过多考虑,切换的方式也很简单,如上文引入相应的依赖即可,我们只需要把上层的逻辑写好即可。

本文案例下载:

本文GitHub地址https://github.com/lenve/JavaEETest/tree/master/Test25-Cache.

更多Spring Boot案例请移步这里从SpringMVC到Spring Boot

以上。

参考资料:

《JavaEE开发的颠覆者 Spring Boot实战》第八章

在Spring Boot中使用数据缓存的更多相关文章

  1. spring boot 中 Cache 的使用

    参考:https://blog.csdn.net/qq_38974634/article/details/80650810 一.JSR107 Java Caching 定义5个核心的接口,分别是Cac ...

  2. Spring Boot 中集成 Redis 作为数据缓存

    只添加注解:@Cacheable,不配置key时,redis 中默认存的 key 是:users::SimpleKey [](1.redis-cli 中,通过命令:keys * 查看:2.key:缓存 ...

  3. Spring Boot中使用EhCache实现缓存支持

     SpringBoot提供数据缓存功能的支持,提供了一系列的自动化配置,使我们可以非常方便的使用缓存.,相信非常多人已经用过cache了.因为数据库的IO瓶颈.一般情况下我们都会引入非常多的缓存策略, ...

  4. Spring Boot中使用缓存

    Spring Boot中使用缓存 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决这一问题非常好的手段之一. 原始的使 ...

  5. Spring Boot中的缓存支持(一)注解配置与EhCache使用

    Spring Boot中的缓存支持(一)注解配置与EhCache使用 随着时间的积累,应用的使用用户不断增加,数据规模也越来越大,往往数据库查询操作会成为影响用户使用体验的瓶颈,此时使用缓存往往是解决 ...

  6. Spring Boot中使用Spring-data-jpa让数据访问更简单、更优雅

    在上一篇Spring中使用JdbcTemplate访问数据库中介绍了一种基本的数据访问方式,结合构建RESTful API和使用Thymeleaf模板引擎渲染Web视图的内容就已经可以完成App服务端 ...

  7. 在Spring Boot中加载初始化数据

    文章目录 依赖条件 data.sql文件 schema.sql 文件 @sql注解 @SqlConfig 注解 在Spring Boot中加载初始化数据 在Spring Boot中,Spring Bo ...

  8. spring boot(三):Spring Boot中Redis的使用

    spring boot对常用的数据库支持外,对nosql 数据库也进行了封装自动化. redis介绍 Redis是目前业界使用最广泛的内存数据存储.相比memcached,Redis支持更丰富的数据结 ...

  9. Spring Boot 整合 Redis 实现缓存操作

    摘要: 原创出处 www.bysocket.com 「泥瓦匠BYSocket 」欢迎转载,保留摘要,谢谢!   『 产品没有价值,开发团队再优秀也无济于事 – <启示录> 』   本文提纲 ...

随机推荐

  1. Zookeeper增删改查

    1.下载Zookeeper http://mirrors.shu.edu.cn/apache/zookeeper/ 这里我选择Zookeeper 3.4.11版本 ZooKeeper 支持某些特定的四 ...

  2. python3全栈开发-异常处理

    一. 什么是异常 异常就是程序运行时发生错误的信号(在程序出现错误时,则会产生一个异常,若程序没有处理它,则会抛出该异常,程序的运行也随之终止),在python中,错误触发的异常如下 而错误分成两种 ...

  3. ES6 new syntax of Default Function Parameters

    Default Function Parameters.md Default Function Parameters function getSum(a,b){ a = (a !== undefine ...

  4. [LeetCode] Cut Off Trees for Golf Event 为高尔夫赛事砍树

    You are asked to cut off trees in a forest for a golf event. The forest is represented as a non-nega ...

  5. org.apache.commons.lang3.tuple.Pair 作为更新参数,XML 中的 Sql 取不到值、报错

    项目用的 Mybatis,今天改一个需求,落地实现是批量更新,且只需要根据主键(id)来更新一个字段(name). 于是,没有犹豫,像下面这样设计了数据结构: 既然是批量更新,那外层肯定是 List ...

  6. java.sql.SQLException: null, message from server: "Host '192.168.126.100' is not allowed to connect to this MySQL server"

  7. [SDOI2006]仓库管理员的烦恼

    题目描述 仓库管理员M最近一直很烦恼,因为他的上司给了他一个艰难的任务:让他尽快想出一种合理的方案,把公司的仓库整理好. 已知公司共有n个仓库和n种货物,由于公司进货时没能很好的归好类,使得大部分的仓 ...

  8. 计蒜客NOIP模拟赛D2T2 直线的交点

    伦伦刚刚在高中学习了解析几何,学会了计算两条直线的交点.这天,老师给她布置了一道作业.在平面上有 nnn 条直线,他们之间有若干交点.给定一对平板(两条平行的直线),问这有多少对直线,他们的交点在这一 ...

  9. 【BZOJ4003】【JLOI2015】城池攻占

    Description 小铭铭最近获得了一副新的桌游,游戏中需要用 m 个骑士攻占 n 个城池.这 n 个城池用 1 到 n 的整数表示.除 1 号城池外,城池 i 会受到另一座城池 fi 的管辖,其 ...

  10. LOJ #6031 字符串

    Description Solution 当 \(k\) 值较小时,发现询问串比较多,串长比较小 然后对 \(Q\) 个询问区间离线跑莫队,一次考虑每一个区间的贡献 假设一个区间 \([i,j]\) ...