Spring自3.1开始就提供了对缓存的支持,核心思路是对方法的缓存,当开发者调用一个方法时,将方法的参数和返回值作为key/value缓存起来,当再次调用该方法时,如果缓存中有数据,就直接从缓存中获取,否则直接调用该方法,这种缓存方式是最有效,因为大部分情况下开发者都是在调用方法。不过Spring中并没有提供缓存的具体实现,而是提供了一套缓存的API,这样开发者就可以根据自己需要来选择合适的缓存并实现它即可。
目前SpringBoot支持如下8种缓存:Simple、Caffeine、JCache(JSR-107)、Redis、Couchbase、Infinispan、Ehcache 2.x和Hazelcast。目前常用的缓存只是其中的两个:Ehcache 2.x和Redis。其实在Spring中,无论开发者使用哪种缓存实现,不同的只是缓存配置,而开发者使用的缓存注解都是一致,因此Spring中的缓存注解和各种缓存实现之间的关系非常类似于JDBC和各种数据库驱动这两者直接的关系一般。

Ehcache 2.x缓存

Ehcache缓存在Java开发领域算的上是比较出名的缓存,而在SpringBoot中开发者只需要一个配置文件就可以将Ehcache集成到自己的项目中。接下来就学习Ehcache 2.x缓存的使用方法:

第一步,创建项目。使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为ehcachespringboot,然后在pom.xml文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加cache依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--添加Ehcache依赖-->
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
<!--添加lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

请注意无论你采用哪种缓存实现方式都需要先引入spring-boot-starter-cache依赖。
第二步,添加缓存配置文件。如果Ehcache的依赖存在,且在classpath下有一个名为ehcache.xml的Ehcache配置文件,那么EhCacheCacheManager将会自动作为缓存的实现。因为首先需要在resources目录下创建一个ehcache.xml文件,作为Ehcache缓存的配置文件,其中的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<ehcache>
<diskStore path="java.io.tmpdir/cache"/>
<defaultCache
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="false"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="120"
/>
<cache name="book_cache"
maxElementsInMemory="10000"
eternal="true"
timeToIdleSeconds="120"
timeToLiveSeconds="120"
overflowToDisk="true"
diskPersistent="true"
diskExpiryThreadIntervalSeconds="600"
/>
</ehcache>

这是一个常规的Ehcache配置文件,其中提供了两个缓存策略,第一个是默认的,另一个名为book_cache。其中name表示缓存名称;maxElementsInMemory表示缓存最大个数;eternal表示缓存对象是否永久有效,一旦设置了永久有效,那么timeout将不起作用;timeToIdleSeconds表示缓存对象在失效前的允许闲置时间(单位:秒),当eternal=false对象不是永久有效时,该属性才会生效;overflowToDisk表示当内存中的对象数量达到maxElementsInMemory时,Ehcache是否将对象写到磁盘中;diskExpiryThreadIntervalSeconds表示磁盘失效线程运行时间间隔。这些都是简单的常规设置,如果开发者想自定义Ehcache配置文件的名称和位置,可以在application.properties配置文件中添加如下配置:

1
2
# 自定义Ehcache配置文件的名称和路径
spring.cache.ehcache.config=classpath:config/another-config.xml

第三步,开启缓存。在项目的入口类上添加@EnableCaching注解,用于开启项目的缓存,代码为:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableCaching
public class EhcachespringbootApplication {
public static void main(String[] args) {
SpringApplication.run(EhcachespringbootApplication.class, args);
}
}

第四步,创建Book实体类。新建pojo包,并创建Book实体类,且实现Serializable接口,里面的代码为:

1
2
3
4
5
6
@Data
public class Book implements Serializable {
private Integer id;
private String name;
private String author;
}

第五步,创建BookDao类。新建dao包,并创建BookDao类,里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Cacheable
public Book getBookById(Integer id){
System.out.println("this is a method for getBookById");
Book book = new Book();
book.setId(id);
book.setName("西游记");
book.setAuthor("吴承恩");
return book;
}

@CachePut(key = "#book.id")
public Book updateBookById(Book book){
System.out.println("this is a method for updateBookById");
book.setName("西游记后传");
return book;
}

@CacheEvict(key = "#id")
public void deleteBookById(Integer id){
System.out.println("this is a method for deleteBookById");
}
}

简单介绍一下上述代码的含义:

  • 首先在BookDao类上添加@Repository注解用于指明它是一个Repository层对象,其次添加@CacheConfig(cacheNames = "book_cache")注解用于指明使用的缓存的名字,这个配置可选,若不使用@CacheConfig注解,则直接在@Cacheable注解中指明缓存名字。
  • 接着在getBookById方法上添加了@Cacheable注解用于表示对该方法进行缓存,默认情况下,缓存的Key是方法的参数,Value则是方法的返回值。当开发者在其他类中调用该方法时,首先会根据调用参数来查看缓存中是否存有相关数据,如果有则直接使用缓存数据,该方法不会执行,如果没有则执行该方法,且将执行成功后的返回值缓存起来。如果是在当前类中调用该方法,则缓存不会生效
  • @Cacheable注解中还有一个属性condition用来描述缓存的执行机制,如@Cacheable(condition="#id%2==0")表示id对2取模为0时才进行缓存,否则不缓存。
  • 如果开发者不想使用默认的Key,也可以使用诸如@CachePut(key = "#book.id")@CacheEvict(key = "#id")的方式来自定义key,前者表示缓存的key为参数Book对象中id的值,而后者表示缓存的key为参数id,除了这种使用参数定义key的方式之外,Spring还提供了一个root对象用于生成key,如下表所示:
属性名称 属性描述 用法示例
methodName 当前方法名 #root.methodName
method 当前方法对象 #root.method.name
caches 当前方法使用的缓存 #root.caches[0].name
target 当前被调用的对象 #root.target
targetClass 当前被调用的对象的class #root.targetClass
args 当前方法参数数组 #root.args[0]

如果上述这些key不能满足开发需求,开发者也可以自定义缓存key的生成器KeyGenerator,相应的代码为:

1
2
3
4
5
6
7
@Component
public class MyGenerator implements KeyGenerator {
@Override
public Object generate(Object o, Method method, Object... objects) {
return Arrays.toString(objects);
}
}

此时之前的BookDao就可以使用自定义的keyGenerator了,这里仅仅粘贴一个getBookById方法使用自定义keyGenerator后的代码逻辑:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Service
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Autowired
private MyGenerator myGenerator;

@Cacheable(keyGenerator = "myGenerator")
public Book getBookById(Integer id){
System.out.println("this is a myGenerator method for getBookById");
Book book = new Book();
book.setId(id);
book.setName("三国演义");
book.setAuthor("罗贯中");
return book;
}
}

这样这个BookDao就成了一个Service,同时在getBookById方法上通过@Cacheable注解的keyGenerator属性来手动设置keyGenerator为自己定义的keyGenerator即可。(依旧还是使用前面的代码)

  • @CachePut(key = "#book.id")注解一般用于数据更新方法上,与@Cacheable注解不同的是,添加了 @CachePut注解的方法每次在执行时都不去检查缓存中是否具有数据,而是直接执行方法,然后将方法的执行结果缓存起来,如果该key对应的数据已经被缓存起来了,它就会覆盖之前的数据,这样可以避免再次加载数据时获取到脏数据。同时@CachePut注解还具有和@Cacheable注解类似的keyGenerator属性,这里就不再赘述了。
  • @CacheEvict(key = "#id")注解一般用于删除方法上,表示移除一个key对应的缓存。@CacheEvict注解有两个特殊的属性:allEntriesbeforeInvocation,其中allEntries表示是否将所有的缓存数据都删除,默认为false;而beforeInvocation表示是否在方法执行前移除缓存中的数据,默认为false,即在方法执行之后移除缓存中的数据。

第六步,创建测试类。新建测试类,对前面的BookDao进行测试,相应的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RunWith(SpringRunner.class)
@SpringBootTest
public class BookDaoTest {
@Autowired
private BookDao bookDao;

@Test
public void contextLoads(){
bookDao.getBookById(1);
bookDao.getBookById(1);
bookDao.deleteBookById(1);
Book book3 =bookDao.getBookById(1);
System.out.println("boo3:"+book3);
Book book = new Book();
book.setId(1);
book.setName("西游记后传");
book.setAuthor("吴承恩");
bookDao.updateBookById(book);
Book book4 =bookDao.getBookById(1);
System.out.println("boo4:"+book4);
}
}

运行结果为:

1
2
3
4
5
6
this is a method for getBookById
this is a method for deleteBookById
this is a method for getBookById
boo3:Book(id=3, name=西游记, author=吴承恩)
this is a method for updateBookById
boo4:Book(id=1, name=西游记后传, author=吴承恩)

一开始执行了两个查询,但是查询方法只打印输出了一次,因为第二次判断第一次存在缓存就使用了缓存,故第二个查询方法不会执行。接着执行了删除方法,删除方法执行后再次执行查询操作,查询方法又被执行了,因为在删除方法中缓存已经被删除了。然后再执行更新方法,更新方法不仅更新了数据,也更新了缓存,所以在最后的查询方法中,查询方法日志没打印,说明该方法没执行,而是使用了缓存中的数据,而缓存中的数据已经被更新了,这就是对上述执行结果的一个分析,如果你之前也能正确的分析出最后的执行结果,说明你已经对Ehcache的缓存机制有了较为深刻的印象。

Redis单机缓存

和Ehcache一样,如果开发者在classpath路径下存在Redis配置文件,且Redis已经配置完毕,那么此时系统就会使用RedisCacheManager作为缓存提供者进行使用。使用单机版的Redis步骤如下:

第一步,创建项目。使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为rediscachespringboot,然后在pom.xml文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加cache依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!--添加data-redis依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
<!--排除lettuce-->
<exclusions>
<exclusion>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</exclusion>
</exclusions>
</dependency>
<!--引入jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
</dependency>
<!--添加lombok依赖-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>

第二步,配置缓存。单机版的Redis缓存只需开发者在application.properties配置文件中进行Redis配置及缓存配置即可,代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
# 缓存设置
# 设置缓存名称,Redis中的Key都有一个前缀,默认前缀就是"缓存名::"
spring.cache.cache-names=c1,c2
# 设置缓存有效期,也就是Redis中Key的过期时间
spring.cache.redis.time-to-live=1800s

# 基本连接信息配置
# 使用Redis库的编号,Redis中提供了16个database,编号从0-15
spring.redis.database=0
# Redis实例的IP地址
spring.redis.host=192.168.2.132
# Redis端口号,默认6379
spring.redis.port=6379
# Redis登录密码
spring.redis.password=123@456

# 连接池基本信息配置
# Redis连接池的最大连接数
spring.redis.jedis.pool.max-active=8
# Redis连接池的最大空闲连接数
spring.redis.jedis.pool.max-idle=8
# Redis连接池的最大阻塞等待时间,默认为-1,表示没有限制
spring.redis.jedis.pool.max-wait=-1ms
# Redis连接池的最小空闲连接数
spring.redis.jedis.pool.min-idle=0

第三步,开启缓存。在项目的入口类上添加@EnableCaching注解,用于开启项目的缓存,代码为:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableCaching
public class RediscachespringbootApplication {
public static void main(String[] args) {
SpringApplication.run(RediscachespringbootApplication.class, args);
}
}

第四步,创建Book实体类。新建pojo包,并创建Book实体类,且实现Serializable接口,里面的代码为:

1
2
3
4
5
6
@Data
public class Book implements Serializable {
private Integer id;
private String name;
private String author;
}

第五步,创建BookDao类。新建dao包,并创建BookDao类,里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Cacheable
public Book getBookById(Integer id){
System.out.println("this is a method for getBookById");
Book book = new Book();
book.setId(id);
book.setName("西游记");
book.setAuthor("吴承恩");
return book;
}

@CachePut(key = "#book.id")
public Book updateBookById(Book book){
System.out.println("this is a method for updateBookById");
book.setName("西游记后传");
return book;
}

@CacheEvict(key = "#id")
public void deleteBookById(Integer id){
System.out.println("this is a method for deleteBookById");
}
}

第六步,创建测试类。新建测试类,对前面的BookDao进行测试,相应的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@RunWith(SpringRunner.class)
@SpringBootTest
public class BookDaoTest {
@Autowired
private BookDao bookDao;

@Test
public void contextLoads(){
bookDao.getBookById(1);
bookDao.getBookById(1);
bookDao.deleteBookById(1);
Book book3 =bookDao.getBookById(1);
System.out.println("boo3:"+book3);
Book book = new Book();
book.setId(1);
book.setName("西游记后传");
book.setAuthor("吴承恩");
bookDao.updateBookById(book);
Book book4 =bookDao.getBookById(1);
System.out.println("boo4:"+book4);
}
}

运行结果为:

1
2
3
4
5
6
this is a method for getBookById
this is a method for deleteBookById
this is a method for getBookById
boo3:Book(id=1, name=西游记, author=吴承恩)
this is a method for updateBookById
boo4:Book(id=1, name=西游记后传, author=吴承恩)

其实除了前三步和Ehcache不同外,其余的和Ehcache步骤完全一致,因此这里就不做过多解释了。

Redis集群缓存

不同于Redis单机缓存,Redis集群缓存的配置要复杂一些,主要体现在配置上,缓存的使用还是三个步骤:1、搭建Redis集群;2、配置缓存;3、使用缓存。接下来就按照这个顺序来学习Redis集群缓存的搭建过程。

搭建Redis集群

在第九篇《整合NoSQL—Redis》中介绍了Redis集群的搭建过程,考虑到资源利用问题,本例子将使用之前的Redis集群,也都是8台Redis实例:4主4备,端口从8001到8008,具体的搭建过程可以参考该篇文章中的详细步骤,这里就不再叙述了。Redis集群搭建成功后,需要通过Spring Data Redis来连接Redis集群,这里后续会介绍,注意这里要求能够在SpringBoot中通过RedisTemplate能成功访问Redis集群。

第一步,创建SpringBoot Web项目并添加依赖。使用spring Initializr构建工具构建一个SpringBoot的Web应用,名称为redisclustercachespringboot,然后在pom.xml文件中添加如下依赖:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!--添加jedis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>2.9.1</version>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
<version>2.1.3.RELEASE</version>
</dependency>
<dependency>
<!--添加数据库连接池依赖-->
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>
<!--添加spring-boot-configuration-processor依赖-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>

第二步,配置集群信息。由于集群节点有多个,可以保存在一个集合中,因此这里的配置文件使用YAML格式较为方便,删除resources目录下的application.properties文件,创建application.yml配置文件,里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
spring:
redis:
cluster:
ports:
- 8001
- 8002
- 8003
- 8004
- 8005
- 8006
- 8007
- 8008
host: 47.100.175.12
poolConfig:
max-total: 8
max-idle: 8
max-wait-millis: -1
min-idle: 0

第三步,配置Redis。新建config包,并在包中创建RedisConfig类,用于返回RedisTemplate对象(因为只是测试,因此就仅仅使用RedisTemplate对象),里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
@Configuration
@ConfigurationProperties("spring.redis.cluster")
public class RedisConfig {
List<Integer> ports;
String host;
JedisPoolConfig jedisPoolConfig;
//getter和setter方法

@Bean
RedisClusterConfiguration redisClusterConfiguration(){
RedisClusterConfiguration configuration = new RedisClusterConfiguration();
List<RedisNode> nodes = new ArrayList<>();
for(Integer port:ports){
nodes.add(new RedisNode(host,port));
}
configuration.setPassword(RedisPassword.of("123@456"));
configuration.setClusterNodes(nodes);
return configuration;
}

@Bean
JedisConnectionFactory jedisConnectionFactory(){
JedisConnectionFactory factory = new JedisConnectionFactory(redisClusterConfiguration(),jedisPoolConfig);
return factory;
}

@Bean
RedisTemplate redisTemplate(){
RedisTemplate redisTemplate = new RedisTemplate();
redisTemplate.setConnectionFactory(jedisConnectionFactory());
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
return redisTemplate;
}
}

第四步,创建实体类。新建pojo包,并在其中新建Book类,里面的代码为:

1
2
3
4
5
6
public class Book implements Serializable {
private Integer id;
private String name;
private String author;
//getter、setter和toString方法
}

配置缓存

当Redis集群搭建成功后,且能够从SpringBoot项目中访问Redis集群后,只需要进行简单的Redis缓存配置就可以使用了。第五步,创建缓存配置类。新建一个RedisCacheConfig配置类,其中的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@Configuration
public class RedisCacheConfig {
@Autowired
RedisConnectionFactory redisConnectionFactory;

@Bean
RedisCacheManager redisCacheManager(){
Map<String, RedisCacheConfiguration> configurationMap =new HashMap<>();
RedisCacheConfiguration redisCacheConfiguration =RedisCacheConfiguration.defaultCacheConfig().prefixKeysWith("envy:")
.disableCachingNullValues().entryTtl(Duration.ofMinutes(30));
configurationMap.put("c1",redisCacheConfiguration);

RedisCacheWriter cacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory);
RedisCacheManager redisCacheManager = new RedisCacheManager(
cacheWriter, RedisCacheConfiguration.defaultCacheConfig(), configurationMap
);
return redisCacheManager;
}
}

解释一下上述代码的含义:

  • 请注意在配置Redis集群是,需要向Spring容器中注入一个JedisConnectionFactory实例,这里是将它注入到RedisCacheConfig配置文件中备用(RedisConnectionFactoryJedisConnectionFactory的父类)。
  • RedisCacheConfig配置文件中提供RedisCacheManager的实例,该实例的构建需要三个参数,第一个参数是一个cacheWriter,直接通过nonLockingRedisCacheWriter方法构建出来极乐;第二个参数是默认的缓存配置;第三个参数是提前定义好的缓存配置。
  • RedisCacheManager构造方法中的第三个参数是提前定义好的缓存参数,它是一个Map类型的参数,该Map中的key就是指缓存名字,value就是该名称的缓存所对应的缓存配置,如key的前缀、缓存过期时间等,若缓存注解中使用的缓存名称不存在于Map中,则使用RedisCacheManager构造方法中第二个参数所定义的缓存策略进行数据缓存。如下面的两个缓存配置:
    1
    2
    @Cacheable(value= "c1")
    @Cacheable(value= "c2")
    显然c1是存在于configurationMap集合中,因此使用的缓存策略是configurationMap集合中c1所对应的缓存策略,c2不存在于configurationMap集合中,因此使用的缓存策略是默认的缓存策略。
  • 本例子中的默认缓存策略是通过调用RedisCacheConfiguration对象的defaultCacheConfig方法来获取的,可以查看一下它的源码:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    public static RedisCacheConfiguration defaultCacheConfig() {
    return defaultCacheConfig((ClassLoader)null);
    }

    public static RedisCacheConfiguration defaultCacheConfig(@Nullable ClassLoader classLoader) {
    DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
    registerDefaultConverters(conversionService);
    return new RedisCacheConfiguration(Duration.ZERO, true, true, CacheKeyPrefix.simple(), SerializationPair.fromSerializer(RedisSerializer.string()), SerializationPair.fromSerializer(RedisSerializer.java(classLoader)), conversionService);
    }
    从上述源码可以看到,默认的缓存过期时间Wie0,即永不过期;第二个参数true表示允许存储null,第三个参数true表示开启key的前缀,第四个参数表示Key的默认前缀是"缓存名::",后续两个参数表示key和value的序列化方式,最后一个参数则是一个类型转换器。
  • 继续回到代码中,里面的configurationMap则是一个自定义的缓存配置,其中设置了key的前缀为"envy:",不过第二个参数则设置了禁止缓存一个null对象,第三个参数则设置了缓存的过期时间为30分钟。

    使用缓存

第六步,开启缓存。在项目的入口类上添加@EnableCaching注解,用于开启项目的缓存,代码为:

1
2
3
4
5
6
7
@SpringBootApplication
@EnableCaching
public class RedisclustercachespringbootApplication {
public static void main(String[] args) {
SpringApplication.run(RedisclustercachespringbootApplication.class, args);
}
}

第七步,创建BookDao类。新建dao包,并创建BookDao类,里面的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
@Repository
public class BookDao {

@Cacheable(value = "c1")
public String getBookById(Integer id){
System.out.println("this is a method for getBookById");
return "这本是西游记";
}

@CachePut(value = "c1")
public String updateBookById(Integer id){
System.out.println("this is a method for updateBookById");
return "这本是2020年全新改版的西游记";
}

@CacheEvict(value = "c1")
public void deleteBookById(Integer id){
System.out.println("this is a method for deleteBookById");
}

@Cacheable(value = "c2")
public String getBookById2(Integer id){
System.out.println("this is a method for getBookById2");
return "这本是红楼梦";
}
}

第八步,创建测试类。新建测试类,对前面的BookDao进行测试,相应的代码为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringRunner.class)
@SpringBootTest
public class BookDaoTest {
@Autowired
private BookDao bookDao;

@Test
public void contextLoads(){
bookDao.getBookById(100);
String book1 =bookDao.getBookById(100);
System.out.println("book1:"+book1);
bookDao.updateBookById(100);
String book2 =bookDao.getBookById(100);
System.out.println("boo2:"+book2);
bookDao.deleteBookById(100);
bookDao.getBookById(100);
bookDao.getBookById2(99);
}
}

缓存小结

本篇学习了SpringBoot中最常见的缓存技术Ehcache和Redis,其中Redis又分为单机缓存和集群缓存。Ehcache部署简单,使用门槛低,操作简单,但是功能比较少,可扩展性较弱;不过Redis则需要单独部署服务器,单机版的Redis缓存基本上做到了开箱即用,集群版的Redis缓存虽然配置较为繁琐,但是具有良好的扩展性和安全性,不过建议开发者在实际开发过程中结合实际情况来选择合适的缓存实现策略。