zoukankan      html  css  js  c++  java
  • 在Spring Boot中使用数据缓存

    春节就要到了,在回家之前要赶快把今年欠下的技术债还清。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实战》第八章

  • 相关阅读:
    Combine 框架,从0到1 —— 4.在 Combine 中使用计时器
    Combine 框架,从0到1 —— 4.在 Combine 中使用通知
    Combine 框架,从0到1 —— 3.使用 Subscriber 控制发布速度
    Combine 框架,从0到1 —— 2.通过 ConnectablePublisher 控制何时发布
    使用 Swift Package Manager 集成依赖库
    iOS 高效灵活地配置可复用视图组件的主题
    构建个人博客网站(基于Python Flask)
    Swift dynamic关键字
    Swift @objcMembers
    仅用递归函数操作逆序一个栈(Swift 4)
  • 原文地址:https://www.cnblogs.com/lenve/p/7530977.html
Copyright © 2011-2022 走看看