10. 搭配redis做文章缓存
redis是一个使用较多的内存键值数据库,这儿的键是字符串类型的标识符,而值可以是字符串、散列、列表、集合和有序集合,也正是因为redis提供了较丰富的值的类型,能够满足不同的使用要求,而且redis的读写是很高效的,所以现在很多系统都将redis作为缓存系统,在使用的时候先从数据库中把数据读取出来,然后写入redis,再次使用该数据时就可以直接从redis中获取,当然如果修改数据的话就要把redis中的对应数据清除。本文主要是介绍springboot+mybatis搭配redis来作为文章的缓存,做法如下:
1. 添加依赖:
1 <dependency> 2 <groupId>org.springframework.boot</groupId> 3 <artifactId>spring-boot-starter-data-redis</artifactId> 4 </dependency>
因为要观察读取数据时是从哪读取到的数据,所以也要配置log4j,并使mybatis能够把sql输出到控制台上,所以也要添加log4j的依赖:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-logging</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-log4j</artifactId> <version>1.3.8.RELEASE</version> </dependency>
2. 在src/main/resources目录下增加log4j.properties文件,并添加以下配置
1 #logger level 2 log4j.rootCategory=DEBUG,stdout,DebugAppender,InfoAppender,ErrorAppender 3 log4j.debug=true 4 log4j.appender.stdout=org.apache.log4j.ConsoleAppender 5 log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 6 log4j.appender.stdout.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n 7 #logger input file 8 log4j.logger.DebugAppender.access=DEBUG 9 log4j.appender.DebugAppender=org.apache.log4j.DailyRollingFileAppender 10 log4j.appender.DebugAppender.File=../logs/debug 11 log4j.appender.DebugAppender.File.datePattern='.'yyyy-MM-dd 12 log4j.appender.DebugAppender.layout=org.apache.log4j.PatternLayout 13 log4j.appender.DebugAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n 14 15 #logger input file 16 log4j.logger.InfoAppender.access=INFO 17 log4j.appender.InfoAppender=org.apache.log4j.DailyRollingFileAppender 18 log4j.appender.InfoAppender.File=../logs/info 19 log4j.appender.InfoAppender.File.datePattern='.'yyyy-MM-dd 20 log4j.appender.InfoAppender.layout=org.apache.log4j.PatternLayout 21 log4j.appender.InfoAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n 22 23 #error log input file 24 log4j.logger.ErrorAppender.access=ERROR 25 log4j.appender.ErrorAppender=org.apache.log4j.DailyRollingFileAppender 26 log4j.appender.ErrorAppender.File=../logs/error 27 log4j.appender.ErrorAppender.File.datePattern='.'yyyy-MM-dd 28 log4j.appender.ErrorAppender.Append = true 29 log4j.appender.ErrorAppender.threshold = ERROR 30 log4j.appender.ErrorAppender.layout=org.apache.log4j.PatternLayout 31 log4j.appender.ErrorAppender.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss,SSS} %5p %c{1}:%L - %m%n
同时在application.properties文件中增加:logging.level.*=DEBUG
3. 在application.properties中添加redis配置
spring.redis.database=0 spring.redis.host=192.168.1.103 spring.redis.port=6379 spring.redis.password= spring.redis.pool.max-active=8 spring.redis.pool.max-wait=-1 spring.redis.pool.max-idle=8 spring.redis.pool.min-idle=0 spring.redis.timeout=0
4. 添加RedisConfig,以开启redis配置:
1 package com.lvniao.blog.config; 2 3 import org.springframework.cache.interceptor.KeyGenerator; 4 import org.springframework.beans.factory.annotation.Value; 5 import org.springframework.cache.CacheManager; 6 import org.springframework.cache.annotation.CachingConfigurerSupport; 7 import org.springframework.cache.annotation.EnableCaching; 8 import org.springframework.context.annotation.Bean; 9 import org.springframework.context.annotation.Configuration; 10 import org.springframework.data.redis.cache.RedisCacheManager; 11 import org.springframework.data.redis.connection.RedisConnectionFactory; 12 import org.springframework.data.redis.core.RedisTemplate; 13 import org.springframework.data.redis.core.StringRedisTemplate; 14 import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; 15 import org.springframework.data.redis.serializer.StringRedisSerializer; 16 17 import java.lang.reflect.Method; 18 import com.fasterxml.jackson.annotation.JsonAutoDetect; 19 import com.fasterxml.jackson.annotation.PropertyAccessor; 20 import com.fasterxml.jackson.databind.ObjectMapper; 21 22 @Configuration 23 @EnableCaching 24 public class RedisConfig extends CachingConfigurerSupport { 25 26 @Value("${spring.redis.host}") 27 private String host; 28 @Value("${spring.redis.port}") 29 private int port; 30 @Value("${spring.redis.timeout}") 31 private int timeout; 32 33 @Bean 34 public KeyGenerator keyGenerator() { 35 return new KeyGenerator() { 36 @Override 37 public Object generate(Object target, Method method, Object... params) { 38 StringBuilder sb = new StringBuilder(); 39 sb.append(target.getClass().getName()); 40 sb.append(":" + method.getName()); 41 for (Object obj : params) { 42 sb.append(":" + obj.toString()); 43 } 44 return sb.toString(); 45 } 46 }; 47 } 48 49 @Bean 50 public CacheManager cacheManager(@SuppressWarnings("rawtypes") RedisTemplate redisTemplate) { 51 RedisCacheManager cacheManager = new RedisCacheManager(redisTemplate); 52 cacheManager.setDefaultExpiration(10000); 53 return cacheManager; 54 } 55 56 @Bean 57 public RedisTemplate<String, String> redisTemplate(RedisConnectionFactory factory) { 58 RedisTemplate<String, String> redisTemplate = new RedisTemplate<String, String>(); 59 redisTemplate.setConnectionFactory(factory); 60 redisTemplate.afterPropertiesSet(); 61 setSerializer(redisTemplate); 62 return redisTemplate; 63 } 64 65 private void setSerializer(RedisTemplate<String, String> template) { 66 Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class); 67 ObjectMapper om = new ObjectMapper(); 68 om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY); 69 om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL); 70 jackson2JsonRedisSerializer.setObjectMapper(om); 71 template.setKeySerializer(new StringRedisSerializer()); 72 template.setValueSerializer(jackson2JsonRedisSerializer); 73 } 74 }
5. 这儿只是使用redis来缓存文章数据,所以在ArticleMapper的getArticleById方法上添加缓存配置,代码如下:
1 @Cacheable(key ="#p0") 2 @Select("select id, name, content, summary, createtime createTime, modifytime modifyTime, publiz, first, author, category from articles where id=#{id}") 3 @Results({ 4 @Result(id=true, column="id", property="id"), 5 @Result(column="name", property="name"), 6 @Result(column="content", property="content"), 7 @Result(column="summary", property="summary"), 8 @Result(column="createTime", property="createTime"), 9 @Result(column="modifyTime", property="modifyTime"), 10 @Result(column="publiz", property="publiz"), 11 @Result(column="first", property="first"), 12 @Result(column="author", property="author", 13 one=@One(select="com.lvniao.blog.mapper.UserMapper.getUserById", fetchType=FetchType.EAGER)), 14 @Result(column="category", property="category", 15 one=@One(select="com.lvniao.blog.mapper.CategoryMapper.getCategoryById", fetchType=FetchType.EAGER)), 16 })
public Article getArticleById(@Param("id") String id);
@Cacheable(key ="#p0") 表示先redis中查找键,如果没找到就从数据库中获取数据,然后把数据写入redis中,这样当第二次调用该方法时,就会从redis中获取数据并返回给调用。其中key ="#p0"表示将第一个参数作为键值。
6. 分别执行两次去掉@Cacheable(key ="#p0") 和含有@Cacheable(key ="#p0") 的操作,然后在控制台中比较两次的日志,截图如下:
从图中可以看到执行同样的调用,左边是从redis中国获取数据,而右边是从数据库中获取数据,所以经过如上步骤,就可以在项目中使用redis了。