10. 搭配redis做文章缓存

Posted 旅鸟

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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>
pom.xml

因为要观察读取数据时是从哪读取到的数据,所以也要配置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>
pom.xml

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
log4j.properties

同时在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
application.properties

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 }
RedisConfig

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 })
ArticleMapper

public Article getArticleById(@Param("id") String id);
@Cacheable(key ="#p0") 表示先redis中查找键,如果没找到就从数据库中获取数据,然后把数据写入redis中,这样当第二次调用该方法时,就会从redis中获取数据并返回给调用。其中key ="#p0"表示将第一个参数作为键值。
6. 分别执行两次去掉@Cacheable(key ="#p0") 和含有@Cacheable(key ="#p0") 的操作,然后在控制台中比较两次的日志,截图如下:

从图中可以看到执行同样的调用,左边是从redis中国获取数据,而右边是从数据库中获取数据,所以经过如上步骤,就可以在项目中使用redis了。

以上是关于10. 搭配redis做文章缓存的主要内容,如果未能解决你的问题,请参考以下文章

Redis

通过MySql自动同步刷新redis

通过MySQL自动同步刷新Redis

在php中redis的用途

在业务代码中使用redis实现缓存效果

Redis缓存击穿,缓存穿透,缓存雪崩解决方案(附代码)