0%

Redis-Java缓存

了解Java中Redis作为缓存如何使用

目的:了解Java中Redis作为缓存如何使用
参考:https://www.cnblogs.com/jinbuqi/p/11038731.html

使用:

1.准备redis环境

1.下载

下载地址:https://github.com/MicrosoftArchive/redis/releases

版本3.0.503.zip

img

2.解压到指定位置

img

3.启动redis服务器:

解压目录中新建文件startup.cmd,内容为:redis-server redis.windows.conf

启动redis服务器:双击startup.cmd

img

img

4.测试

打开同一个文件夹下的 redis-cli.exe
输入测试语句

1
2
3
set key value

get key

结果:

1
“value”

2.java中使用

1.项目环境

我的环境 idea:2018.3.3 jdk:1.8.0_131
idea新建springboot项目

maven添加jar包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<!--注释掉,开启junit-->
<!--<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>-->
</dependency>

<!--Web-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<!-- Redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

<!--json包-->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-pool2</artifactId>
</dependency>

<!-- log -->
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-api -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.slf4j/slf4j-log4j12 -->
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
</dependency>

2.添加配置文件

application.properties中添加

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# REDIS (RedisProperties)
# Redis数据库索引(默认为0)
spring.redis.database=0
# Redis服务器地址
spring.redis.host=localhost
# Redis服务器连接端口
spring.redis.port=6379
# Redis服务器连接密码(默认为空)
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

新建log4j.properties

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
log4j.rootLogger=CONSOLE,FILE
log4j.addivity.org.apache=true

# 应用于控制台
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.Threshold=INFO
log4j.appender.CONSOLE.Target=System.out
log4j.appender.CONSOLE.Encoding=UTF-8
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

# 每天新建日志
log4j.appender.A1=org.apache.log4j.DailyRollingFileAppender
log4j.appender.A1.File=D:/log4j/log
log4j.appender.A1.Encoding=UTF-8
log4j.appender.A1.Threshold=DEBUG
log4j.appender.A1.DatePattern='.'yyyy-MM-dd
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L : %m%n

#应用于文件
log4j.appender.FILE=org.apache.log4j.FileAppender
log4j.appender.FILE.File=E:/log4j/file.log
log4j.appender.FILE.Append=false
log4j.appender.FILE.Encoding=UTF-8
log4j.appender.FILE.layout=org.apache.log4j.PatternLayout
log4j.appender.FILE.layout.ConversionPattern=[framework] %d - %c -%-4r [%t] %-5p %c %x - %m%n

3.包结构

image-20200522161701680

4.配置Redis

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
/**
* Description: redis配置 配置序列化方式以及缓存管理器
*
* @author hxr
* @version 1.0
*/
@EnableCaching//开启以注解方式使用缓存。
@Configuration//这是一个配置类
@AutoConfigureAfter(RedisAutoConfiguration.class)
public class RedisConfig {

/**
* Description: json序列化
*/
@Bean
public RedisSerializer<Object> jackson2JsonRedisSerializer() {
//使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<Object>(Object.class);

ObjectMapper mapper = new ObjectMapper();
mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
mapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
serializer.setObjectMapper(mapper);
return serializer;
}

/**
* Description:配置自定义redisTemplate
*
* @param connectionFactory
* @return
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
template.setConnectionFactory(connectionFactory);
template.setValueSerializer(jackson2JsonRedisSerializer());
//使用StringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jackson2JsonRedisSerializer());
template.afterPropertiesSet();
return template;
}

/**
* 配置缓存管理器
* @param redisConnectionFactory
* @return
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory) {
// 生成一个默认配置,通过config对象即可对缓存进行自定义配置
RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig();
// 设置缓存的默认过期时间,也是使用Duration设置
config = config.entryTtl(Duration.ofMinutes(1))
// 设置 key为string序列化
.serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
// 设置value为json序列化
.serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(jackson2JsonRedisSerializer()))
// 不缓存空值
.disableCachingNullValues();

// 设置一个初始化的缓存空间set集合
Set<String> cacheNames = new HashSet<>();
cacheNames.add("timeGroup");
cacheNames.add("user");

// 对每个缓存空间应用不同的配置
Map<String, RedisCacheConfiguration> configMap = new HashMap<>();
configMap.put("timeGroup", config);
configMap.put("user", config.entryTtl(Duration.ofSeconds(120)));

// 使用自定义的缓存配置初始化一个cacheManager
RedisCacheManager cacheManager = RedisCacheManager.builder(redisConnectionFactory)
// 一定要先调用该方法设置初始化的缓存名,再初始化相关的配置
.initialCacheNames(cacheNames)
.withInitialCacheConfigurations(configMap)
.build();
return cacheManager;
}

/**
* 缓存的key是 包名+方法名+参数列表
*/
@Bean
public KeyGenerator keyGenerator() {
return (target, method, objects) -> {
StringBuilder sb = new StringBuilder();
sb.append(target.getClass().getName());
sb.append("::" + method.getName() + ":");
for (Object obj : objects) {
sb.append(obj.toString());
}
return sb.toString();
};
}
}

5.实体类pojo

使用了lombok

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
package com.xiaoruiit.redis_cache.pojo;

import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.*;

/**
* Description:
*
* @author hxr
* @version 1.0
*/

@Data
@NoArgsConstructor //无参构造
@AllArgsConstructor //有参构造
public class User {
private long id;
private String nickname;
private String mobile;

@JsonProperty(access = JsonProperty.Access.WRITE_ONLY)//在输出的Json数据中隐藏密码,只能输入不输出
private String password;
private String role;

}

6.Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
* Description:
*
* @author hxr
* @version 1.0
*/
@RestController
@EnableAutoConfiguration
@RequestMapping("/user")
public class UserController {

@Resource
private UserService userService;

@Resource
private RedisTemplate<String, Object> redis;

@RequestMapping(value = "{id}", method = RequestMethod.GET, produces = "application/json")
public User getUserById(@PathVariable long id){
User user = userService.getUserById(id);
return user;
}

@RequestMapping(value = "{id}/change-nick", method = RequestMethod.POST, produces = "application/json")
public User updateNickname(@PathVariable long id) throws Exception{
String nickname = "ww-" + Math.random();
User user = userService.updateUserNickname(id, nickname);
return user;
}

@RequestMapping(value = "{id}/change-nick", method = RequestMethod.POST, produces = "application/json")
public User updateMobile(@PathVariable long id) throws Exception{
String mobile = "134" + Math.random();
User user = userService.updateUserNickname(id, mobile);
return user;
}

// 使用RedisTemplate访问redis服务器
@RequestMapping(value="/redis", method=RequestMethod.GET, produces="application/json")
public String redis() throws Exception {

// 设置键"key",值"value"
redis.opsForValue().set("key", "value");
String value = (String) redis.opsForValue().get("key");

return value;
}

}

7.Service + ServiceImpl

  • @Cacheable - 表明对应方法的返回结果可以被缓存,首次调用后,下次就从缓存中读取结果,方法不会再被执行了。

  • @CachePut - 更新缓存,方法每次都会执行

  • @CacheEvict - 清除缓存,方法每次都会执行

    Service

1
2
3
4
5
6
7
8
9
10
11
12
/**
* Description:
*
* @author hxr
* @version 1.0
*/
public interface UserService {

public User getUserById(long userId);
public User updateUserNickname(long userId, String nickname);
public User updateUserMobile(long userId, String mobile);
}

ServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
/**
* Description:
*
* @author hxr
* @version 1.0
*/
@Service
public class UserServiceImpl implements UserService {

private static final Logger log = LoggerFactory.getLogger(UserServiceImpl.class);

private User user = new User(11, "zs", "13400000000", "123456", "admin");

@Cacheable(value = "user", key = "#userId") //表明对应方法的返回结果可以被缓存,首次调用后,下次就从缓存中读取结果,可以查到时,方法不会被执行。
@Override
public User getUserById(long userId) {
log.info("加载user");
return user;
}

@CacheEvict(value = "user", key= "#userId") //清除缓存,方法每次都会执行
@Override
public User updateUserNickname(long userId, String nickname) {
log.info("修改名字,清除缓存");
user.setNickname(nickname);
return user;
}

@CachePut(value = "user", key= "#userId") //更新缓存,方法每次都会执行
@Override
public User updateUserMobile(long userId, String mobile) {
log.info("修改手机,更新缓存");
user.setMobile(mobile);
return user;
}
}

8.启动redis监控

进入redis安装目录,双击redis-cli.exe,输入monitor

image-20200522163608886

9.APIPost测试q

启动springboot项目,打开Apipost

1.@Cacheable测试

发送请求,查看redis监控器中的变化

image-20200522164136415

image-20200522164207296

image-20200522164320735

再发送三次

image-20200522164431496

image-20200522164451522

加载user只打印了一次,方法内部只执行了一次

image-20200522164949723

2.@CacheEvict测试

发送两次请求

image-20200522164734057

image-20200522164834405

image-20200522164927084

3.CachePut测试

发送两次请求

image-20200522165145493

image-20200522165212982

image-20200522165257318