09-SpringBoot的缓存-1

09-SpringBoot的缓存-1

本文初概的介绍了SpringBoot的缓存,并介绍了EhCache的初级使用。更多深入的用法,请其他查看专业文档。

目录


image.png

1.什么是缓存

  • 一种以为键值对方式存在于内存的数据。一旦数据被缓存,用户的请求可不通过代码逻辑快速提供数据反馈。

  • 在键值对中,用LRU(last recently used)算法来保证对最近不常访问的数据进行清除

  • 由于存在内存中,通常一断电,缓存数据就Over了。

2.解决的问题

  • 提升性能

    主要用于读多写少的场景

  • 缓解数据库压力

    比如商城秒杀

3.使用缓存的场景

  • 数据实时性要求不高

  • 对性能要求比较高

4.SpringBoot中对缓存的支持

  • JCache

  • EhCache

  • Hazelcast

  • Infinispan

  • Couchbase

  • Redis

  • Caffeine

  • Simple

  • EhCache和Redis是目前比较主流的缓存使用方式

5. EhCache

单机,配置简单,快速上手,单机上性能好(JVM操作)。

劣势:拓展性性能较差。在集群方案中,基本看不到应用身影。

实现

本实现采用的SpringBoot版本信息如下:


org.springframework.boot
spring-boot-starter-parent
2.2.0.M4

下面我们来一步一步实现。

SpringBoot添加依赖


    ……
    
        org.springframework.boot
        spring-boot-starter-cache
    
    
        net.sf.ehcache
        ehcache
    

SpringBoot缓存配置

缓存配置一般放在resources目下,名为一个ehcache.xml文件,如果没有,请自行创建。

修改配置文件位置

通常配置的位置在resouces目录下,如果要修改,请在application.properties中进行修改:

spring.cache.ehcache.config=classpath:config/another-config.xml
默认配置
    

部分配置的说明:

​ name 缓存名唯一标识
​ maxElementsInMemory="1000" 内存中最大缓存对象数
​ eternal="false" 是否永久缓存
​ timeToIdleSeconds="3600" 缓存清除时间 默认是0 即永不过期
​ timeToLiveSeconds="0" 缓存存活时间 默认是0 即永不过期
​ overflowToDisk="true" 缓存对象达到最大数后,将其写入硬盘
​ maxElementsOnDisk="10000" 磁盘最大缓存数
​ diskPersistent="false" 磁盘持久化
​ diskExpiryThreadIntervalSeconds="120" 磁盘缓存的清理线程运行间隔
​ memoryStoreEvictionPolicy="FIFO" 缓存清空策略
​ FIFO 先进先出
​ LFU less frequently used 最少使用
​ LRU least recently used 最近最少使用

自定义配置

在这里定义一个DiskCache,代表缓存会存储在磁盘中:

    
    

配置的全貌为:




    
    
     
    
    

SpringBoot缓存启动定义

重在@EnableCaching标签

@SpringBootApplication
@EnableCaching
public class Demo1Application {
    public static void main(String[] args) {
        SpringApplication.run(Demo1Application.class, args);
    }
}

SpringBoot缓存功能实现

Dao实现

我们先来普及一下几个注解,如下:

@CacheConfig

在Dao类中进行声明,如果需要进行自定义类声明,需要配合CacheNames

@Cacheable

使用在方法的定义,标明是缓存方法,使用在查询方法上。

@CachePut

在使用update,以及insert方法的时候,需要使用这个注解,同时需要声明key,它代表了update的时候,key是使用哪一个(SQL上的术语)。

一般这么写@CachePut(key = "book.id"),book是方法入参的参数,在Update的时候,通常使用的是一个对象对吧。

这里有一个点需要注意,在定义@CachePut方法的时候,一定要将save对象返回,也就是方法return save对象,否则在后续get的时候,可能出现对象获取null的情况!切记切记。

@CacheEvict

在删除的时候使用,依然需要声明key,一般这样声明@CacheEvict(key = "#id"),id为我们需要删除对象的主键,也是我们删除方法的入参。

最后,来一个整体示例:

import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.CachePut;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;

import com.example.demo.beans.Book;

@Repository
@CacheConfig(cacheNames = "DiskCache")
public class BookDao {
    private Book mBook;
    /**
     *  初始化Book对象。方便做test
     * @return
     */
    public Book initBookCache() {
        mBook = new Book();
        mBook.setId(1);
        mBook.setName("西游记");
        mBook.setAuthor("罗贯中");
        return mBook;
    }
    
        
    @Cacheable
    public Book getBookById(Integer id) {
        System.out.println("getBookById:未使用缓存");
        if(id.equals(mBook.getId())) { // 模拟数据库查询
            return mBook;
        }
        return null;
    }
        
    @CachePut(key = "#mBook.id")
    public Book updateBookById(Book mBook) {
        System.out.println("updateBook:未使用缓存");
        this.mBook = mBook;  // 模拟数据库存储
        return mBook; // 请注意,这里一定要返回!否则缓存数据不会更新!!!!!
    }
    
    @CacheEvict(key = "#id")
    public void deleteBookById(Integer id) {
        System.out.println("deleteBookById:未使用缓存");
        // 这里执行删除操作,同时使用@CacheEvict,将会把缓存中的数据也清除。
        // 删除后,调用getBookById,不会使用缓存。
    }

}
Bean实现

实现接口Serializabe

import java.io.Serializable;

public class Book implements Serializable{
        
    private static final long serialVersionUID = 1L;
    
    private Integer id;
    private String name;
    private String author;
    
    // ……getter/setter
}

SpringBoot测试

使用通常的测试即可,有如下注解需要了解

@RunWith(SpringRunner.class)

@Spring BootTest

@Autowired

@Test

@Before,@BeforeClass,@After,@AfterClass,@Igonore,都可以使用

在代码中,如果使用了缓存,是不会进入方法的,所以我们需要结合打印来理解。部分注释已经写在代码上了。

package com.example.demo;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;

import com.example.demo.beans.Book;
import com.example.demo.services.BookDao;

import static org.hamcrest.CoreMatchers.containsString;

import org.junit.Assert;

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

    @Autowired
    BookDao mBookDao;

    @Test
    public void contextLoads() {
        mBookDao.initBookCache();

        // 查询测试
        mBookDao.getBookById(1); // 方法打印
        mBookDao.getBookById(1); // 使用缓存:不应打印

        // 删除测试
        mBookDao.deleteBookById(1); // 方法打印
        Book mBook = mBookDao.getBookById(1); // 若已经删除,这里再获取,应该打印未使用缓存

        // 升级测试
        Book mBook1 = new Book();
        mBook1.setId(1);
        mBook1.setName("西游记2");
        mBook1.setAuthor("罗贯中");
        mBookDao.updateBookById(mBook1);// 打印update
        mBook = mBookDao.getBookById(1); // 不应打印
        System.out.println(mBook.toString()); // 看到升級項
        Assert.assertThat(mBook.toString(),containsString("西游记2"));

        // insert测试
        mBook = mBookDao.getBookById(1);
        mBook.setId(10);
        mBookDao.updateBookById(mBook);
        mBook = mBookDao.getBookById(10); // 应打印
        System.out.println(mBook.toString()); 
        Assert.assertThat(mBook.toString(), containsString("id:10"));
    }
}

问题:

Eclipse中出现问题:no tests found with test runner 'JUnit 5'

解决:

问题在Eclipse中出现,问题在于需要解决JUnit5切换为4。解决办法是:在对应的项目,右键->Run Configurations ,左面选择JUnit,右面就会看到有个Test runner的选项,选择JUnit4。

提示不推荐使用Assert类型

解决:把import junit.framework.TestCase;的引入,改为import org.junit.Assert;

引用

  • Spring boot cache的Simple Cache更新数据后获取的缓存数据为null问题,感谢作者:hj楚ing
  • Junit4中的新断言assertThat的使用方法,感谢作者:飘飘雪

你可能感兴趣的:(09-SpringBoot的缓存-1)