banner
NEWS LETTER

SpringBoot项目整合Redis作缓存

  • Home
  • springboot-redisCache
Scroll down

在SpringBoot项目中使用Redis作缓存,既可避免频繁读取后端数据库,又可优化读取时间
本案例使用工具:IDEA,Postman,Redis,Mysql
本案例GitHub地址:https://github.com/limenggen/springboot-redis-demo

1、开启redis远程访问

vi redis.conf
修改bing 127.0.0.1注释掉
修改protected-mode 属性值为no
修改daemonize属性值为yes(启动后台运行)

Redis安装过程:https://limenggen.github.io/CentOS7_redis/

2、启动redis

./redis-server redis.conf

  • 测试连接
  • redis-cli -h 192.168.137.101 -p 6379 # (-a 密码)

3、创建测试数据

在mysql数据库中创建测试数据

users.sql
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;
-- ----------------------------
-- Table structure for users
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
`uid` int(11) NOT NULL,
`username` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_bin NULL DEFAULT NULL,
`salary` int(40) NULL DEFAULT NULL,
PRIMARY KEY (`uid`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb4 COLLATE = utf8mb4_bin ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES (123, 'cat', 'miaomiao', 4000);

SET FOREIGN_KEY_CHECKS = 1;

Mysql安装过程:https://limenggen.github.io/CentOS7-mysql5-7/

4、创建springboot项目

  • 项目结构

5、添加pom.xml依赖

pom.xml >folded
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
<dependencies>
<!-- 快速搭建并开发web项目 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- mybatis 与 spring boot 2.x的整合包 -->
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.2</version>
</dependency>
<!--mysql JDBC驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- redis -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<!-- 统一不同的缓存技术 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<!-- 添加lombok插件 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
  • 相关依赖需要注意版本
  • 本案例依赖版本:
  • spring-boot-starter-web:2.3.4
  • mybatis-spring-boot-starter:2.3.4
  • spring-boot-starter-data-redis:2.3.4
  • spring-boot-starter-cache:2.3.4
  • lombok:1.18.12

6、修改application.yml

修改application.properties文件为application.yml

application.yml >folded
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
server:
port: 8081

#数据库连接
spring:
datasource:
url: jdbc:mysql://192.168.137.102:3306/redis?useUnicode=true
driver-class-name: com.mysql.cj.jdbc.Driver
username: root
password: root

## Redis 配置
redis:
## Redis数据库索引(默认为0)
database: 0
## Redis服务器地址
host: 192.168.137.102
## Redis服务器连接端口
port: 6379
## Redis服务器连接密码(默认为空)
password:
jedis:
pool:
## 连接池最大连接数(使用负值表示没有限制)
#spring.redis.pool.max-active=8
max-active: 8
## 连接池最大阻塞等待时间(使用负值表示没有限制)
#spring.redis.pool.max-wait=-1
max-wait: -1
## 连接池中的最大空闲连接
#spring.redis.pool.max-idle=8
max-idle: 8
## 连接池中的最小空闲连接
#spring.redis.pool.min-idle=0
min-idle: 0
## 连接超时时间(毫秒)
timeout: 1200
  • 数据库驱动版本高于6.0:com.mysql.cj.jdbc.Driver
  • 数据库驱动版本低于6.0:com.mysql.jdbc.Driver

7、创建redisConfig配置类

RedisConfig.java

RedisConfig.java >folded
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
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.CachingConfigurerSupport;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.*;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.time.Duration;

/**
* redis配置类
*
*/
@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
/**
* 选择redis 作为默认缓存工具
*/
@Bean
public CacheManager cacheManager(RedisConnectionFactory redisConnectionFactory){
RedisCacheConfiguration redisCacheConfiguration = RedisCacheConfiguration.defaultCacheConfig().entryTtl(Duration.ofHours(1));// 设置缓存有效期一小时
return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(redisConnectionFactory)).cacheDefaults(redisCacheConfiguration).build();
}

/**
* retemplate 相关配置
*/
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory){
RedisTemplate<String, Object> template = new RedisTemplate<>();
// 配置连接工厂
template.setConnectionFactory(factory);
// 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
Jackson2JsonRedisSerializer jacksonSerial = new Jackson2JsonRedisSerializer(Object.class);
ObjectMapper om = new ObjectMapper();
// 指定要序列化的域,field,get和set,以及修饰符范围,any是都有包括private和public
om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
// 指定序列化输入的类型,类必须是非final修饰的,final修饰的类,比如String,Integer等会抛出异常
om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
jacksonSerial.setObjectMapper(om);

// 值采用json序列化
template.setValueSerializer(jacksonSerial);
// 使用SringRedisSerializer来序列化和反序列化redis的key值
template.setKeySerializer(new StringRedisSerializer());

// 设置hash key和value序列化模式
template.setHashKeySerializer(new StringRedisSerializer());
template.setHashValueSerializer(jacksonSerial);
template.afterPropertiesSet();

return template;
}

/**
* 对hash类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public HashOperations<String, String, Object> hashOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForHash();
}

/**
* 对redis字符串类型数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ValueOperations<String, Object> valueOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForValue();
}

/**
* 对链表类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ListOperations<String, Object> listOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForList();
}

/**
* 对无序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public SetOperations<String, Object> setOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForSet();
}

/**
* 对有序集合类型的数据操作
*
* @param redisTemplate
* @return
*/
@Bean
public ZSetOperations<String, Object> zSetOperations(RedisTemplate<String, Object> redisTemplate) {
return redisTemplate.opsForZSet();
}
}

8、创建实体类

User.java

User.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@AllArgsConstructor
@NoArgsConstructor
public class User implements Serializable {

private static final long serialVerisionUID = 1L;
private int uid;
private String userName;
private String passWord;
private int salary;
}
  • User类中需要添加无参构造函数,否则会报错
    com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
    无法构造的实例 com.morgan.entity.User (不存在创建者,如默认构造函数): 无法从对象值反序列化

9、创建mapper接口

UserDao.java

UserDao.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import com.morgan.entity.User;
import org.apache.ibatis.annotations.*;

import java.util.List;

@Mapper
public interface UserDao {

@Select("select * from users")
List<User> queryAll();

@Select("select * from users where uid = #{id}")
User findUserById(int id);

@Update("update users set username = #{user.userName},password = #{user.password},salary = #{user.salary} where uid = #{user.uid}")
int updateUser(@Param("user") User user);

@Delete("delete from users where uid = #{id}")
int deleteUserById(int id);
}
  • updateUser方法因传参为:实例类
  • 需要:@Param(“user”)
  • SQL语句的参数需要留意书写格式

10、创建service类

UserService.java

UserService.java >folded
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
import com.morgan.entity.User;
import com.morgan.mapper.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.concurrent.TimeUnit;

@Service
public class UserService {
@Autowired
private UserDao userDao;

@Autowired
private RedisTemplate redisTemplate;

public List<User> queryAll(){
return userDao.queryAll();
}

/**
* 获取用户测流:先从缓存中获取用户,没有则去数据表中数据,再将数据写入缓存
*/
public User findUserById(int id){
String key = "user_" + id;
ValueOperations<String, User> operations = redisTemplate.opsForValue();
// 判断redis中是否有键位key的缓存
Boolean hasKey = redisTemplate.hasKey(key);
if(hasKey){
User user = operations.get(key);
return user;
}else{
User user = userDao.findUserById(id);
operations.set(key, user, 5, TimeUnit.HOURS);
return user;
}
}

/**
* 更新用户策略:先更新数据表,成功之后,删除原来的缓存,再更新缓存
*/
public int updateUser(User user){
ValueOperations<String, User> operations = redisTemplate.opsForValue();
int result = userDao.updateUser(user);
System.out.println("result:"+ result);
if(result != 0){
String key = "user_" + user.getUid();
Boolean hasKey = redisTemplate.hasKey(key);
if(hasKey)
redisTemplate.delete(key);
// 再将更新后的数据加入缓存
User userById = userDao.findUserById(user.getUid());
if(userById != null)
operations.set(key, userById, 3, TimeUnit.HOURS);
}
return result;
}

/**
* 删除用户策略:删除数据表中数据,然后删除缓存
*/
public int deleteUserById(int id){
int result = userDao.deleteUserById(id);
String key = "user_" + id;
if( result != 0){
Boolean hasKey = redisTemplate.hasKey(id);
if(hasKey)
redisTemplate.delete(key);
}
return result;
}
}

11、创建controller类

UserController.java

UserController.java >folded
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
import com.morgan.entity.User;
import com.morgan.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
@RequestMapping("/redis")
public class UserController {
@Autowired
private UserService userService;

@RequestMapping("/queryAll")
public List<User> queryAll(){
return userService.queryAll();
}

@RequestMapping("/findUserById")
public Map<String, Object> findUserById(@RequestParam int id){
User user = userService.findUserById(id);
Map<String, Object> result = new HashMap<>();
result.put("uid", user.getUid());
result.put("username", user.getUserName());
result.put("password", user.getPassword());
result.put("salary", user.getSalary());
return result;
}

@RequestMapping("updateUser")
public String updateUser(){
User user = new User(123,"morgan","morgan",400);
int result = userService.updateUser(user);
if(result != 0)
return "update success";
return "update fail";
}

@RequestMapping("/deleteUserById")
public String deleteUserById(@RequestParam int id){
int result = userService.deleteUserById(id);
if(result != 0)
return "delete success";
return "delete fail";
}
}

12、启动项目

使用postman测试访问:http://localhost:8081/redis/queryAll

请随意打赏

评论