简介
内存的速度远远大于硬盘的速度,当我们需要重复获取相同的数据的时候,一次又一次的请求数据库或远程服务,导致大量时间都消耗在数据库查询或远程方法调用上面,性能下降,这时候就需要使用到缓存技术了。
本文介绍SpringBoot 如何使用redis做缓存,如何对redis缓存进行定制化配置(如key的有效期)以及初始化redis做缓存。使用具体的代码介绍了@Cacheable,@CacheEvict,@CachePut,@CacheConfig等注解及其属性的用法。
Spring缓存支持
Spring定义了 org.springframework.cache.CacheManager
和 org.springframework.cache.Cache
接口来统一不同缓存技术。其中CacheManager是Spring提供的各种缓存技术抽象接口,内部使用Cache接口进行缓存的增删改查操作,我们一般不会直接和Cache打交道。
针对不同的缓存技术,Spring有不同的CacheManager实现类,定义如下表:
CacheManager | 描述 |
---|---|
SimpleCacheManager | 使用简单的Collection存储缓存数据,用来做测试用 |
ConcurrentMapCacheManager | 使用ConcurrentMap存储缓存数据 |
EhCacheCacheManager | 使用EhCache作为缓存技术 |
GuavaCacheManager | 使用Google Guava的GuavaCache作为缓存技术 |
JCacheCacheManager | 使用JCache(JSR-107)标准的实现作为缓存技术,比如Apache Commons JCS |
RedisCacheManager | 使用Redis作为缓存技术 |
在我们使用任意一个实现的CacheManager的时候,需要注册实现Bean:
@Bean
public EhCacheCacheManager cacheManager(CacheManager cacheManager) {
return new EhCacheCacheManager(cacheManager);
}
当然,各种缓存技术都有很多其他配置,但是配置cacheManager是必不可少的。
声明式缓存注解
Spring提供4个注解来声明缓存规则,如下表所示:
注解 | 说明 |
---|---|
@Cacheable | 方法执行前先看缓存中是否有数据,如果有直接返回。如果没有就调用方法,并将方法返回值放入缓存 |
@CachePut | 无论怎样都会执行方法,并将方法返回值放入缓存 |
@CacheEvict | 将数据从缓存中删除 |
@Caching | 可通过此注解组合多个注解策略在一个方法上面 |
@Cacheable 、@CachePut 、@CacheEvict都有value属性,指定要使用的缓存名称,而key属性指定缓存中存储的键。
代码实践
项目整体结构
EhCacheConfig文件
package com.yj.config;
import net.sf.ehcache.config.CacheConfiguration;
import java.lang.reflect.Method;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurer;
import org.springframework.cache.ehcache.EhCacheCacheManager;
import org.springframework.cache.interceptor.CacheErrorHandler;
import org.springframework.cache.interceptor.CacheResolver;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.yj.entity.Product;
import com.yj.entity.User;
//@Configuration
public class EhCacheConfig implements CachingConfigurer {
@Value("${ehcache.cacheNames}")
private String[] cacheNames;
@Bean(destroyMethod = "shutdown")
public net.sf.ehcache.CacheManager ehCacheManager() {
net.sf.ehcache.config.Configuration config = new net.sf.ehcache.config.Configuration();
for(String cacheName:cacheNames){
CacheConfiguration cacheConf = new CacheConfiguration();
cacheConf.setName(cacheName);
cacheConf.setMemoryStoreEvictionPolicy("LRU");
cacheConf.setMaxEntriesLocalHeap(1000);
config.addCache(cacheConf);
}
return net.sf.ehcache.CacheManager.newInstance(config);
}
@Bean
@Override
public CacheManager cacheManager() {
return new EhCacheCacheManager(ehCacheManager());
}
@Bean
@Override
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
for (Object obj : params) {
sb.append(obj.getClass().getSimpleName());
if(obj instanceof User){
sb.append("_"+((User)obj).getId());
}else if(obj instanceof Product){
sb.append("_"+((Product)obj).getId());
}
}
return sb.toString();
}
};
}
@Override
public CacheResolver cacheResolver() {
return null;
}
@Override
public CacheErrorHandler errorHandler() {
return null;
}
}
MybatisConfig文件
package com.yj.config;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@MapperScan("com.yj.dao")
public class MybatisConfig {
}
RedisCacheConfig文件
package com.yj.config;
import java.lang.reflect.Method;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.yj.entity.Product;
import com.yj.entity.User;
@Configuration
public class RedisCacheConfig extends CachingConfigurerSupport {
@Bean
public CacheManager cacheManager(RedisTemplate redisTemplate) {
RedisCacheManager redisCacheManager = new RedisCacheManager(redisTemplate);
redisCacheManager.setDefaultExpiration(300);
return redisCacheManager;
}
@Bean
public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) {
StringRedisTemplate template = new StringRedisTemplate(factory);
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jackson2JsonRedisSerializer.setObjectMapper(om);
template.setValueSerializer(jackson2JsonRedisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
template.afterPropertiesSet();
return template;
}
@Bean
public KeyGenerator keyGenerator() {
return new KeyGenerator() {
@Override
public Object generate(Object target, Method method, Object... params) {
StringBuilder sb = new StringBuilder();
for (Object obj : params) {
sb.append("cache:"+obj.getClass().getSimpleName()+":"+obj.getClass().getSimpleName());
if(obj instanceof User){
sb.append("_"+((User)obj).getId());
}else if(obj instanceof Product){
sb.append("_"+((Product)obj).getId());
}
}
return sb.toString();
}
};
}
}
CacheController文件
package com.yj.controller;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yj.entity.BusinessException;
import com.yj.service.CacheService;
@RestController
@RequestMapping("/cache")
public class CacheController {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private CacheService cacheService;
@RequestMapping("/getCacheType")
public String getCacheType() {
String result = null;
try {
result = cacheService.getCacheType();
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return result;
}
@RequestMapping("/clear")
public String clearCache() {
String result = null;
try {
result = cacheService.clearCache();
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return result;
}
}
ProductController文件
package com.yj.controller;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yj.entity.Product;
import com.yj.entity.BusinessException;
import com.yj.service.ProductService;
@RestController
@RequestMapping("/product")
public class ProductController {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private ProductService productService;
@RequestMapping("/add")
public Product add(@RequestBody Product product) {
try {
productService.add(product);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return product;
}
@RequestMapping("/delete")
public Product delete(@RequestBody Product product) {
try {
productService.delete(product);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return product;
}
@RequestMapping("/update")
public Product update(@RequestBody Product product) {
try {
productService.update(product);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return product;
}
@RequestMapping("/get")
public Product get(@RequestBody Product product) {
try {
product = productService.get(product);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return product;
}
@RequestMapping("/clear")
public String clear() {
String result = null;
try {
result=productService.clearCache();
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return result;
}
}
UserController文件
package com.yj.controller;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import com.yj.entity.BusinessException;
import com.yj.entity.User;
import com.yj.service.UserService;
@RestController
@RequestMapping("/user")
public class UserController {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private UserService userService;
@RequestMapping("/add")
public User add(@RequestBody User user) {
try {
userService.add(user);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return user;
}
@RequestMapping("/delete")
public String delete(@RequestBody User user) {
String result = null;
try {
result = userService.delete(user);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return result;
}
@RequestMapping("/update")
public User update(@RequestBody User user) {
try {
userService.update(user);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return user;
}
@RequestMapping("/get")
public User get(@RequestBody User user) {
try {
user = userService.get(user);
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return user;
}
@RequestMapping("/clear")
public String clear() {
String result = null;
try {
result=userService.clearCache();
} catch (BusinessException e) {
log.error("发生异常"+e.getMessage());
}
return result;
}
}
ProductDao文件
package com.yj.dao;
import com.yj.entity.Product;
public interface ProductDao{
void add(Product book);
Product get(Product book);
void update(Product book);
void delete(Product book);
}
UserDao文件
package com.yj.dao;
import com.yj.entity.User;
public interface UserDao{
void add(User user);
User get(User user);
void update(User user);
void delete(User user);
}
BusinessException文件
package com.yj.entity;
import org.apache.commons.lang3.exception.ExceptionUtils;
public class BusinessException extends RuntimeException {
private static final long serialVersionUID = -8138602623241348983L;
/**
* 错误代码,默认为未知错
*/
private String errorCode = "UNKNOW_ERROR";
/**
* 错误信息中的参数
*/
protected String[] errorArgs = null;
/**
* 兼容纯错误信息,不含error code,errorArgs的情
*/
private String errorMessage = null;
public BusinessException() {
super();
}
public BusinessException(Throwable e) {
super(e);
this.errorMessage = ExceptionUtils.getStackTrace(e);
}
public BusinessException(String errorCode, String[] errorArgs) {
super(errorCode);
this.errorCode = errorCode;
this.errorArgs = errorArgs;
}
public BusinessException(String errorCode, String errorMessage) {
super(errorCode);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
}
public BusinessException(String errorCode, String errorMessage, String[] errorArgs) {
super(errorCode);
this.errorCode = errorCode;
this.errorMessage = errorMessage;
this.errorArgs = errorArgs;
}
public BusinessException(String errorCode, String[] errorArgs, Throwable cause) {
super(cause);
this.errorCode = errorCode;
this.errorArgs = errorArgs;
}
public BusinessException(String errorCode, String errorArg, Throwable cause) {
super(cause);
this.errorCode = errorCode;
this.errorArgs = new String[] { errorArg };
}
public BusinessException(String errorMessage) {
super(errorMessage);
this.errorMessage = errorMessage;
}
/**
* 获得出错信息. 读取i18N properties文件中Error Code对应的message,并组合参数获得i18n的出错信
*/
public String getMessage() {
if (errorMessage != null) {
return errorMessage;
}
if (super.getMessage() != null)
return super.getMessage();
return errorMessage;
}
public String getMessageDetail() {
return errorMessage;
}
public String getErrorCode() {
return errorCode;
}
}
Product文件
package com.yj.entity;
import java.io.Serializable;
public class Product implements Serializable{
private static final long serialVersionUID = -3143542456642754711L;
private String id;
private String name;
private Integer price;
private String imgUrl;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getPrice() {
return price;
}
public void setPrice(Integer price) {
this.price = price;
}
public String getImgUrl() {
return imgUrl;
}
public void setImgUrl(String imgUrl) {
this.imgUrl = imgUrl;
}
@Override
public String toString() {
return "Product [id=" + id + ", name=" + name + ", price=" + price + ", imgUrl=" + imgUrl + "]";
}
}
User文件
package com.yj.entity;
import java.io.Serializable;
public class User implements Serializable{
private static final long serialVersionUID = -166121995881423259L;
public String id;
public String name;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + "]";
}
}
CacheService文件
package com.yj.service;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.stereotype.Service;
import com.yj.entity.BusinessException;
@Service
public class CacheService {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private CacheManager cacheManager;
@CacheEvict(value = {"cache:Product:Product","cache:User:User"}, allEntries = true)
public String clearCache() throws BusinessException {
log.info("clearCache");
return "清空所有缓存成功";
}
public String getCacheType() throws BusinessException {
String result;
try {
result = cacheManager.getClass().getName();
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("获取缓存类型异常");
}
return result;
}
}
InitCache文件,用于当使用Redis作为缓存时,启停项目时,清空Redis内所有缓存的数据
package com.yj.service;
import java.util.Set;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
@Component
public class InitCache implements CommandLineRunner,DisposableBean{
protected Logger log = Logger.getLogger(getClass());
public static final String CACHE_KEY_PREFIX = "cache:";
@Autowired
private RedisTemplate redisTemplate;
@Override
public void run(String... args) throws Exception {
String pattern = CACHE_KEY_PREFIX + "*";
RedisConnection connection = redisTemplate
.getConnectionFactory().getConnection();
Set<byte[]> caches = connection.keys(pattern.getBytes());
if(!caches.isEmpty()){
connection.del(caches.toArray(new byte[][]{}));
}
log.info("项目启动,清空redis中的缓存");
}
@Override
public void destroy() throws Exception {
String pattern = CACHE_KEY_PREFIX + "*";
RedisConnection connection = redisTemplate
.getConnectionFactory().getConnection();
Set<byte[]> caches = connection.keys(pattern.getBytes());
if(!caches.isEmpty()){
connection.del(caches.toArray(new byte[][]{}));
}
log.info("项目停止,清空redis中的缓存");
}
}
ProductService文件
package com.yj.service;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
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.Service;
import com.yj.dao.ProductDao;
import com.yj.entity.Product;
import com.yj.entity.BusinessException;
@Service
@CacheConfig(cacheNames = { "cache:Product:Product" },keyGenerator="keyGenerator")
public class ProductService {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private ProductDao productDao;
@CachePut
public Product add(Product product) throws BusinessException {
try {
log.info("create");
productDao.add(product);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("添加商品出现异常");
}
return product;
}
@CacheEvict
public Product delete(Product product) throws BusinessException {
try {
log.info("delete:" + product.getId());
productDao.delete(product);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("删除商品出现异常");
}
return product;
}
@CachePut
public Product update(Product product) throws BusinessException {
try {
log.info("update");
productDao.update(product);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("更新商品出现异常");
}
return product;
}
@Cacheable
public Product get(Product product) throws BusinessException {
log.info("get:" + product.getId());
return productDao.get(product);
}
@CacheEvict(allEntries = true)
public String clearCache() {
log.info("clearCache");
return "清空商品缓存成功";
}
}
UserService文件
package com.yj.service;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
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.Service;
import com.yj.dao.UserDao;
import com.yj.entity.BusinessException;
import com.yj.entity.User;
@Service
@CacheConfig(cacheNames = {"cache:User:User"},keyGenerator="keyGenerator")
public class UserService {
protected Logger log = Logger.getLogger(getClass());
@Autowired
private UserDao userDao;
@CachePut
public User add(User user) throws BusinessException {
try {
log.info("create");
userDao.add(user);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("添加用户出现异常");
}
return user;
}
@CacheEvict
public String delete(User user) throws BusinessException {
try {
log.info("delete:" + user.getId());
userDao.delete(user);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("删除用户出现异常");
}
return "删除用户成功";
}
@CachePut
public User update(User user) throws BusinessException {
try {
log.info("update");
userDao.update(user);
} catch (Exception e) {
e.printStackTrace();
throw new BusinessException("更新用户出现异常");
}
return user;
}
@Cacheable
public User get(User user) throws BusinessException {
log.info("get:" + user.getId());
return userDao.get(user);
}
@CacheEvict(allEntries = true)
public String clearCache() throws BusinessException {
log.info("clearCache");
return "清空用户缓存成功";
}
}
Application文件
package com.yj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
@SpringBootApplication
@EnableCaching
public class Application{
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class, args);
}
}
Product.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yj.dao.ProductDao">
<insert id="add" parameterType="com.yj.entity.Product">
insert into product (`id`, `name`,`price`,`imgUrl`) values (#{id},#{name},#{price},#{imgUrl})
</insert>
<delete id="delete" parameterType="com.yj.entity.Product">
delete from product where id=#{id}
</delete>
<update id="update" parameterType="com.yj.entity.Product">
update product set name=#{name},price=#{price},imgUrl=#{imgUrl} where id =#{id}
</update>
<select id="get" parameterType="com.yj.entity.Product" resultType="com.yj.entity.Product">
select id,name,price,imgUrl from product where id =#{id}
</select>
</mapper>
User.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.yj.dao.UserDao">
<insert id="add" parameterType="com.yj.entity.User">
insert into user (`id`, `name`) values (#{id},#{name})
</insert>
<delete id="delete" parameterType="com.yj.entity.User">
delete from user where id=#{id}
</delete>
<update id="update" parameterType="com.yj.entity.User">
update user set name=#{name} where id =#{id}
</update>
<select id="get" parameterType="com.yj.entity.User" resultType="com.yj.entity.User">
select id,name from user where id =#{id}
</select>
</mapper>
application.properties文件
spring.application.name=cache
spring.datasource.url = jdbc:mysql://192.168.124.129:3306/docker?useSSL=false
spring.datasource.username = root
spring.datasource.password = 123456
spring.datasource.driverClassName = com.mysql.jdbc.Driver
mybatis.mapperLocations=classpath:mapper/*.xml
spring.redis.host=192.168.124.129
spring.redis.database=0
spring.redis.port=6379
spring.redis.password=
spring.redis.pool.max-idle=8
spring.redis.pool.min-idle=0
spring.redis.pool.max-active=100
spring.redis.pool.max-wait=-1
ehcache.cacheNames=Product,User
logback.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter" />
<conversionRule conversionWord="wex" converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter" />
<conversionRule conversionWord="wEx" converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter" />
<!-- 彩色日志格式 -->
<property name="CONSOLE_LOG_PATTERN"
value="${CONSOLE_LOG_PATTERN:-%clr(%d{yyyy-MM-dd HH:mm:ss.SSS}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}}" />
<!-- 控制台打印日志的相关配置 -->
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}<!--%d{yyyy-MM-dd HH:mm:ss.SSS} [%level] [%class:%line] - %m%n--></pattern>
<charset>utf8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>debug</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
</appender>
<!-- 文件保存日志的相关配置 -->
<appender name="file" class="ch.qos.logback.core.rolling.RollingFileAppender">
<file>logs/cache.log</file>
<encoder>
<pattern>${CONSOLE_LOG_PATTERN}</pattern>
<charset>utf8</charset>
</encoder>
<filter class="ch.qos.logback.classic.filter.LevelFilter">
<level>DEBUG</level>
<onMatch>ACCEPT</onMatch>
<onMismatch>ACCEPT</onMismatch>
</filter>
<!-- 循环政策:基于时间创建日志文件 -->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<fileNamePattern>logs/%d{yyyy-MM-dd}/cache.%d{yyyy-MM-dd}.log</fileNamePattern>
<maxHistory>30</maxHistory>
</rollingPolicy>
</appender>
<logger name="com.yj" level="debug" />
<!-- 基于dubug处理日志:具体控制台或者文件对日志级别的处理还要看所在appender配置的filter,如果没有配置filter,则使用root配置 -->
<root level="info">
<appender-ref ref="console" />
<appender-ref ref="file" />
</root>
</configuration>
pom.xml文件
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.yj</groupId>
<artifactId>Cache</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>
<name>Cache</name>
<url>http://maven.apache.org</url>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.2.RELEASE</version>
<relativePath />
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</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>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8</version>
</dependency>
</dependencies>
</project>
验证
验证cache的类型
访问
http://127.0.0.1:8080/cache/getCacheType
当项目没有引入任何Redis跟EhCache依赖,并且没配置Redis配置Bean跟EhCache配置Bean时,显示默认的cache采用的是ConcurrentMapCacheManager
org.springframework.cache.concurrent.ConcurrentMapCacheManager
启用Redis作为缓存时,显示
org.springframework.data.redis.cache.RedisCacheManager
启用ehcache作为缓存时,显示
org.springframework.cache.ehcache.EhCacheCacheManager
我们主要验证Redis作为缓存的情况
①访问add接口
http://127.0.0.1:8080/product/add
数据库和Redis都存入了数据,查看Redis
②访问update接口
http://127.0.0.1:8080/product/update
发现数据库和Redis内的数据都已经更新了
③访问get接口
http://127.0.0.1:8080/product/get
获取到了结果,并且控制台没有输出SQL语句,说明没有访问数据库,是从Redis中获取到了缓存的数据
④ 访问delete接口
http://127.0.0.1:8080/product/delete
数据库和Redis中的该id的数据被清空了
再次访问get接口查询该id的商品时,会重新查询数据库,打印出SQL,并且将查询结果存入Redis中
⑤访问clear接口
http://127.0.0.1:8080/product/clear
数据库和Redis中所有product的数据都被清空了
再次访问get接口时,会重新查询数据库,打印出SQL,并且将查询结果存入了Redis中