1. 创建项目,添加缓存依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</dependency>
添加缓存配置文件
如果Ehcache的依赖存在,并且在classpath下有一个名为ehcache.xml的Ehcache配置文件,那么EhCacheCacheManager将会自动作为缓存的实现。因此,在resources目录下创建ehcache.xml文件作为Ehcache缓存的配置文件:
<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>
提供了两个缓存策略,一个是默认的,另一个名为book_cache。
- name:缓存名称
- maxElementsInMemory:缓存最大个数
- eternal:缓存对象是否永久有效,一旦设置了永久有效,timeout将不起作用
- timeToIidleSeconds:缓存对象在失效前的允许闲置时间(单位:秒);当eternal=false时,该属性才生效
- overflowToDisk表示当内存中的对象数量达到maxElementsInmemory时,Ehcache是否将对象写到磁盘中
- diskExpiryThreadIntervalSeconds:磁盘失效线程运行时间间隔
如果想自定义配置文件的名称和位置,可以在application.properties中添加如下配置:
spring.cache.ehcache.config=classpath:config/another-config.xml
3. 开启缓存
@SpringBootApplication
@EnableCaching
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
4. 创建BookDao
@Repository
@CacheConfig(cacheNames = "book_cache")
public class BookDao {
@Cacheable
public Book getBookById(Integer id){
System.out.println("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("updateBookById");
book.setName("三国演义2");
return book;
}
@CacheEvict(key = "#id")
public void deleteBookById(Integer id){
System.out.println("deleteBookById");
}
}
如果不想使用默认的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:
@Component
public class MyKeyGenerator implements KeyGenerator {
@Override
public Object generate(Object o, Method method, Object... objects) {
return Arrays.toString(objects);
}
}
5. 创建测试类
@SpringBootTest
@RunWith(SpringRunner.class)
class DemoApplicationTests {
@Autowired
BookDao bookDao;
@Test
void contextLoads() {
bookDao.getBookById(1);
bookDao.getBookById(1);
bookDao.deleteBookById(1);
Book b3 = bookDao.getBookById(1);
System.out.println("b3:" + b3);
Book b = new Book();
b.setName("三国演义");
b.setAuthor("罗贯中");
b.setId(1);
bookDao.updateBookById(b);
Book b4 = bookDao.getBookById(1);
System.out.println("b4:" + b4);
}
}
执行方法,控制台打印如下:
getBookById
deleteBookById
getBookById
b3:Book{id=1, name='三国演义', author='罗贯中'}
updateBookById
b4:Book{id=1, name='三国演义2', author='罗贯中'}
一开始执行了两个查询,但是查询方法只打印了一次,因为第二次使用了缓存。接下来执行删除方法,删除方法执行完之后再次执行查询,查询方法又被执行了,因为在删除方法中缓存已经被删除了。再接下来执行更新方法,更新方法中不仅更新数据,也更新了缓存,所以在最后的查询方法中,查询方法日志没打印,说明该方法没执行,而是使用了缓存中的数据,而缓存中的数据已经被更新了。