8.5.3 使用@CacheEvict清除缓存

8.5.3 使用@CacheEvict清除缓存

@CacheEvict注解修饰的方法可用于清除缓存,使用@CacheEvict注解时可指定如下属性。

属性 描述
value 必需属性。用于指定该方法用于清除哪个缓存区的数据
key 通过SpEL表达式显式指定缓存的key
allEntries 该属性指定是否清空整个缓存区
beforeInvocation 该属性指定是否在执行方法之前清除缓存。默认是在方法成功完成之后才清除缓存。
condition 该属性指定一个SpEL表达式,只有当该表达式为true时才清除缓存。

程序示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
E:\workspace_QingLiangJiJavaEEQiYeYingYongShiZhang5\CacheEvict
└─src\
├─beans.xml
├─ehcache.xml
├─lee\
│ └─SpringTest.java
└─org\
└─crazyit\
└─app\
├─domain\
│ └─User.java
└─service\
├─impl\
│ └─UserServiceImpl.java
└─UserService.java

UserServiceImpl类增加两个方法,分别用于清空指定缓存和清空缓存。下面是UserServiceImpl类的代码。

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
36
37
package org.crazyit.app.service.impl;

import org.crazyit.app.domain.User;
import org.crazyit.app.service.UserService;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Service;

@Service("userService")
@Cacheable(value = "users")
public class UserServiceImpl implements UserService
{
public User getUsersByNameAndAge(String name, int age)
{
System.out.println("--正在执行findUsersByNameAndAge()查询方法--");
return new User(name, age);
}
public User getAnotherUser(String name, int age)
{
System.out.println("--正在执行findAnotherUser()查询方法--");
return new User(name, age);
}
// 指定根据name、age参数清除缓存
@CacheEvict(value = "users")
public void evictUser(String name, int age)
{
System.out.println("--正在清空" + name + " , " + age + "对应的缓存--");
}
// 指定清除user缓存区所有缓存数据
@CacheEvict(
value = "users",
allEntries = true)
public void evictAll()
{
System.out.println("--正在清空整个缓存--");
}
}

上面程序中
第一个@CacheEvict注解只是指定了value="users"一个属性,这表明该注解用于清除users缓存区中的数据,程序将会根据传入的nameage参数清除对应的数据。
第二个@CacheEvict注解则指定了allEntries=true,这表明该方法将会清空整个users缓存区。
使用如下主程序来测试它。

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
36
37
package lee;

import org.crazyit.app.service.UserService;
import org.crazyit.app.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringTest
{
public static void main(String[] args)
{
@SuppressWarnings("resource")
ApplicationContext ctx = new ClassPathXmlApplicationContext(
"beans.xml");
UserService us = ctx.getBean("userService", UserService.class);
// 调用us对象的2个带缓存的方法,系统会缓存两个方法返回的数据
User u1 = us.getUsersByNameAndAge("孙悟空", 500);
User u2 = us.getAnotherUser("猪八戒", 400);
// 调用evictUser()方法清除缓存中指定的数据
us.evictUser("猪八戒", 400);
// 由于前面根据"猪八戒", 400缓存的数据已经被清除了,
// 因此下面代码会重新执行,方法返回的数据将被再次缓存。
User u3 = us.getAnotherUser("猪八戒", 400); // ①
System.out.println(u2 == u3); // 输出false
// 由于前面前面已经缓存了参数为"孙悟空", 500的数据,
// 因此下面代码不会重新执行,直接利用缓存中的数据。
User u4 = us.getAnotherUser("孙悟空", 500); // ②
System.out.println(u1 == u4); // 输出true
// 清空整个缓存。
us.evictAll();
// 由于整个缓存都已经被清空,因此下面两行代码都会重新执行
User u5 = us.getAnotherUser("孙悟空", 500);
User u6 = us.getAnotherUser("猪八戒", 400);
System.out.println(u1 == u5); // 输出false
System.out.println(u3 == u6); // 输出false
}
}

上面程序中us.evictUser("猪八戒", 400);这行代码只是清除了缓存区中"猪八戒",400"对应的数据,因此上面程序在①号代码处需要重新执行该方法;但在②号代码处将可直接利用缓存区中的数据,无须重新执行该方法。
程序中第二行粗体字代码清空了整个缓存,因此第二行粗体字代码以后的两次调用方法都需要重新执行(因为缓存区中已经没数据了)。
执行该程序可以看到如下输出:

1
2
3
4
5
6
7
8
9
10
11
--正在执行findUsersByNameAndAge()查询方法--
--正在执行findAnotherUser()查询方法--
--正在清空猪八戒 , 400对应的缓存--
--正在执行findAnotherUser()查询方法--
false
true
--正在清空整个缓存--
--正在执行findAnotherUser()查询方法--
--正在执行findAnotherUser()查询方法--
false
false