共计 5641 个字符,预计需要花费 15 分钟才能阅读完成。
微信公众号:一个优秀的废人。如有问题,请后台留言,反正我也不会听。
前言
两个月没更新原创了,实在惭愧。没有借口,就是因为自己懒了。最近看了「刻意学习」,这本书谈的是学习与行动的关系,书中提到了「持续行动」这个概念,意思就是:我们要去实实在在地去做一些事情,而且是每天都做,才能称之为「持续行动」。看完这本书以后,我意识到我必须要做些什么,那就是写作。
Redis 简介
Redis 是一个开源的,基于内存的键值数据存储,用作数据库,缓存和消息代理。在实现方面,Key-Value 存储代表 NoSQL 空间中最大和最老的成员之一。Redis 支持数据结构,如字符串,散列,列表,集和带范围查询的有序集。
在 spring data redis 的框架,可以很容易地编写,通过提供一个抽象的数据存储使用 Redis 的键值存储的 Spring 应用程序。
非关系型数据库,基于内存,存取数据的速度不是关系型数据库所能比拟的
redis 是键值对 (key-value) 的数据库
数据类型
- 字符串类型 string
- 散列类型 hash
- 列表类型 list
- 集合类型 set
- 有序集合类型 zset
其中,因为 SpringBoot 约定大于配置的特点,只要我们加入了 spring-data-redis 依赖包并配置 Redis 数据库,SpringBoot 就会帮我们自动配置一个 RedisTemplate,利用它我们就可以按照以下方式操作对应的数据类型,在下面实战中我将会对这五种数据进行操作。
- redisTemplate.opsForValue(); // 操作字符串
- redisTemplate.opsForHash(); // 操作 hash
- redisTemplate.opsForList(); // 操作 list
- redisTemplate.opsForSet(); // 操作 set
- redisTemplate.opsForZSet(); // 操作有序 set
开发环境
- SpringBoot 2.1.6 RELEASE
- spring-data-redis 2.1.9 RELEASE
- Redis 3.2
- IDEA
- JDK8
- mysql
关于如何安装 Redis 这里不再赘述,请自行搜索引擎搜索解决。
pom 依赖
<dependencies> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-data-jpa</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-data-redis</artifactId> | |
</dependency> | |
<dependency> | |
<groupId>mysql</groupId> | |
<artifactId>mysql-connector-java</artifactId> | |
<scope>runtime</scope> | |
</dependency> | |
<dependency> | |
<groupId>org.projectlombok</groupId> | |
<artifactId>lombok</artifactId> | |
<optional>true</optional> | |
</dependency> | |
<!-- https://mvnrepository.com/artifact/com.alibaba/fastjson --> | |
<dependency> | |
<groupId>com.alibaba</groupId> | |
<artifactId>fastjson</artifactId> | |
<version>1.2.58</version> | |
</dependency> | |
<dependency> | |
<groupId>org.springframework.boot</groupId> | |
<artifactId>spring-boot-starter-test</artifactId> | |
<scope>test</scope> | |
</dependency> | |
</dependencies> |
配置文件
spring: | |
datasource: | |
driver-class-name: com.mysql.cj.jdbc.Driver | |
url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true | |
username: root | |
password: 123456 | |
jpa: | |
hibernate: | |
ddl-auto: update #ddl-auto: 设为 create 表示每次都重新建表 | |
show-sql: true | |
redis: | |
host: localhost | |
port: 6379 | |
# Redis 数据库索引(默认为 0)database: 1 | |
jedis: | |
pool: | |
#连接池最大连接数 | |
max-active: 8 | |
#最小空闲连接 | |
min-idle: 0 | |
#最大阻塞等待时间,负值表示没有限制 | |
max-wait: -1ms | |
#最大空闲连接 | |
max-idle: 8 | |
#连接超时时间 (毫秒) | |
timeout: 20ms | |
# 无密码可不写 | |
# password: |
为什么乱码?
/** | |
* 添加字符串 | |
*/ | |
@Test | |
public void setString(){redisTemplate.opsForValue().set(USERKEY,"nasus"); | |
redisTemplate.opsForValue().set(AGEKEY,24); | |
redisTemplate.opsForValue().set(CITYKEY,"清远"); | |
} |
首先是添加字符串类型的数据。它的运行结果如下:
如何解决乱码
我们可以看到插入的数据是乱码的,这是因为 SpringBoot 自动配置的这个 RedisTemplate 是没有设置数据读取时的 key 及 value 的序列化方式的。所以,我们要写一个自己的 RedisTemplate 并设置 key 及 value 的序列化方式才可以正常操作 Redis。如下:
@Configuration | |
public class RedisConfig { | |
private final RedisTemplate redisTemplate; | |
@Autowired | |
public RedisConfig(RedisTemplate redisTemplate) {this.redisTemplate = redisTemplate;} | |
@Bean | |
@SuppressWarnings("unchecked") | |
public RedisTemplate<String, Object> redisTemplate() {RedisSerializer<String> stringSerializer = new StringRedisSerializer(); | |
//RedisSerializer<Object> jsonString = new GenericToStringSerializer<>(Object.class); | |
RedisSerializer<Object> jsonString = new FastJsonRedisSerializer<>(Object.class); | |
// String 的 key 和 hash 的 key 都采用 String 的序列化方式 | |
redisTemplate.setKeySerializer(stringSerializer); | |
redisTemplate.setHashKeySerializer(stringSerializer); | |
// value 都采用 fastjson 的序列化方式 | |
redisTemplate.setValueSerializer(jsonString); | |
redisTemplate.setHashValueSerializer(jsonString); | |
return redisTemplate; | |
} | |
} |
这时,再次运行上面的单元测试,结果就正常了。
操作 List
/** | |
* 添加、获取 LIST | |
*/ | |
@Test | |
public void setList(){List<Student> students = studentService.findStudentList(); | |
log.info("students size = {}", students.size()); | |
// 循环向 studentList 左添加值 | |
students.forEach(value->redisTemplate.opsForList().leftPush(LISTKEY,value)); | |
// 向 studentList 右添加值 | |
Student student = new Student(); | |
student.setId(10); | |
student.setAge(24); | |
student.setName("rightPush"); | |
redisTemplate.opsForList().rightPush(LISTKEY,student); | |
// 获取值 | |
log.info("studentList->{}",redisTemplate.opsForList().range(LISTKEY,0,10)); | |
} |
这里需要说一下,leftpush 和 rightpush 的区别,前者是在 key 对应 list 的头部添加元素,也就是我们常说的后来居上,List<Student> 下标最大的元素在这个 list 里面处于第一位;而后者则是 在 key 对应 list 的尾部添加元素,刚好和前者相反。
获取值,代码这里获取的是 0 到 10 行的数据,控制台打印结果:
[{"name":"优秀","id":9,"age":22}, {"name":"冯某华","id":8,"age":25}, {"name":"蓝某城","id":7,"age":25}, {"name":"优秀","id":6,"age":22}, {"name":"冯某华","id":5,"age":25}, {"name":"蓝某城","id":4,"age":25}, {"name":"冯某华","id":3,"age":25}, {"name":"蓝某城","id":2,"age":25}, {"name":"废人","id":1,"age":22}, {"name":"rightPush","id":10,"age":24}]
添加 List 结果:
这里注意 1 到 9 行的 id 值刚好是相反的,而正常情况下,我从 mysql 数据中查出来的值是这样的:
因此,验证了 leftpush 和 rightpush 的区别。
操作 set
/** | |
* 添加和获取 Set | |
*/ | |
@Test | |
public void setAndGetSet(){List<String> usernameList = new ArrayList<>(); | |
usernameList.add("nasus"); | |
usernameList.add("nasus"); | |
usernameList.add("一个优秀的废人"); | |
// 循环向添加值 | |
usernameList.forEach(value->redisTemplate.opsForSet().add(SETKEY,value)); | |
log.info("取出 usernameSet->{}",redisTemplate.opsForSet().members(SETKEY)); | |
} | |
/** | |
* 删除 Set | |
*/ | |
@Test | |
public void delSet(){redisTemplate.opsForSet().remove(SETKEY,"nasus"); | |
} |
Redis 的 set 数据结构跟 java 的 hashset 数据结构一样,也是无序且不重复。所以我代码里 add 了两个 nasus 字符串,其实只 add 了一个 nasus。结果如下:
操作 hash
分别作了 hash 的添加、删除以及获取,代码如下:这里需要说明一下的是,hash 的 hash 有两个键可以设置,其中第一个是 redis 中的键,而第二个是具体每条数据的 hashkey。
/** | |
* 添加 hash | |
*/ | |
@Test | |
public void setHash(){List<Student> students = studentService.findStudentList(); | |
// 添加 | |
for (Student student : students){redisTemplate.opsForHash().put(HASHKEY, student.getId().toString(), student); | |
} | |
} | |
/** | |
* 删除 hash | |
*/ | |
@Test | |
public void delHash(){Student student = studentService.findStudentById(0); | |
// 删除 | |
redisTemplate.opsForHash().delete(HASHKEY,JSON.toJSONString(student)); | |
} | |
/** | |
* 获取 Hash | |
*/ | |
@Test | |
public void getHash(){List<Student> students = redisTemplate.opsForHash().values(HASHKEY); | |
log.info("values = {}", students); | |
} |
添加 hash 操作结果:
获取 hash 操作结果:
源码地址
https://github.com/turoDog/Demo/tree/master/springboot_redis_demo
推荐阅读
SpringBoot | 自动配置原理
后语
如果本文对你哪怕有一丁点帮助,请帮忙点好看。你的好看是我坚持写作的动力。
另外,关注之后在发送 1024 可领取免费学习资料。
资料详情请看这篇旧文:Python、C++、Java、Linux、Go、前端、算法资料分享