• 在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实战》第八章

  • 相关阅读:
    rotate list
    使用存取方法来设置Property value
    模拟创建类变量,static变量加类方法,单例
    下拉刷新常规代码
    强制横竖屏间切换
    友盟分享
    快速下拉刷新动画
    把电脑上的视频导入苹果6
    xcrun: error: active developer path ("/Volumes/Xcode/Xcode-beta.app/Contents/Developer") does not exist, use `xcode-select --swi
    iOS 刚刚,几分钟前,几小时前,几天前,几月前,几年前
  • 原文地址:https://www.cnblogs.com/lenve/p/7530977.html
Copyright © 2020-2023  润新知