Spring之缓存

简介

     内存的速度远远大于硬盘的速度,当我们需要重复获取相同的数据的时候,一次又一次的请求数据库或远程服务,导致大量时间都消耗在数据库查询或远程方法调用上面,性能下降,这时候就需要使用到缓存技术了。

     本文介绍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中

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

猎户星座。

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值