本文为瑞吉外卖项目的后续内容,在此特别感谢黑马程序员的课程
Redis入门
Redis简介
关系型数据库(RDBMS):MySQL、Oracl、DB2、SQLServer
非关系型数据库(NoSql):Redis、Mongo DB、MemCached
- Redis应用场景:缓存、消息队列、任务队列、分布式锁
下载与安装
Windows安装Redis
Linux安装Redis
- Linux系统安装Redis步骤:
- 将Redis安装包上传到Linux
- 解压安装包,改成你自己的redis版本,路径我习惯解压到
/usr/local
1
| tar -zxvf redisVersion.tar.gz -C /usr/local
|
- 安装Redis的依赖环境gcc,我的云服务器已经装过了,本地的Linux还没装
- 进入
/usr/local/redis根目录
,进行编译
1 2 3 4 5
| cd /usr/local/redis根目录
make
|
- 进入redis的src目录,进行安装
1 2 3 4
| cd /usr/local/redis根目录/src
make install
|
服务启动与停止
Linux启动与停止
- 进入到
/src
目录下,执行redis-server
即可启动服务,默认端口号为6379
1 2 3 4 5
| cd /usr/local/redis根目录/src
./redis-server
|
Linux设置后台运行
- 进入到redis根目录下,修改配置redis.conf文件
1 2 3 4 5
| cd /usr/local/redis根目录
vim redis.conf
|
- 找到
daemonize on
字段,将其修改为daemonize yes
- 在redis根目录以redis.conf作为配置文件在后台运行
1
| src/redis-server ./redis.conf
|
Linux开启密码校验
- 还是修改redis.conf配置文件,找到
requirepass
这行,将其注释去掉,并在后面写上自己的密码
- 然后杀掉原进程再重新启动
1 2 3 4 5
| src/redis-server ./redis.conf
src/redis-cli -h localhost -p 6379 -a 密码
|
Linux开启远程连接
- 还是修改redis.conf配置文件,找到
bind 127.0.0.1
这行,把这行注释掉
- 之后设置防火墙,开启6379端口
1 2 3 4 5 6 7 8
| firewall-cmd --zone=public --add-port=6379/tcp --permanent
firewall-cmd --reload
firewall-cmd --zone=public --list-ports
|
云服务器开放端口,需要进入后台手动开启,通过命令行开启的端口无效,查看开放的端口确实有6379,但是实际上是没开放的,我昨天因为这个,连不上MySQL(3306端口没开,我以为开了),找了俩小时的原因
- 最后在Windows的redis根目录下,按住Shift+右键打开PowerShell窗口,连接Linux的Redis
1
| .\redis-cli.ext -h 服务器地址 -p 6379 -a 密码
|
Redis数据类型
介绍
Redis存储的是key-value结构的数据,其中key是字符串类型,value有5中常用的数据类型
- 字符串:String
- 哈希:Hash
- 列表:List
- 集合:Set
- 有序集合:Sorted Set
字符串(String)常用命令
命令 |
描述 |
SET key value |
设置指定key的值 |
GET key |
获取指定key的值 |
SETEX key seconds value |
设置指定key的值,并将key的过期时间设为seconds秒 |
SETNX key value |
只有在key不存在时设置key的值 |
哈希(Hash)常用命令
Redis Hash
是一个String
类型的Field
和Value
的映射表,Hash
特别适合用于存储对象
命令 |
描述 |
HSET key field value |
将哈希表key 中的字段field的值设为value |
HGET key field |
获取存储在哈希表中指定字段的值 |
HDEL key field |
删除存储在哈希表中的指定字段 |
HKEYS key |
获取哈希表中所有字段 |
HVALS key |
获取哈希表中所有值 |
HGETALL key |
获取在哈希表中指定key的所有字段和值 |
列表(List)常用命令
Redis List
是简单的字符串列表,按照插入顺序排序
命令 |
描述 |
LPUSH key value1 [value2] |
将一个或多个值插入到列表头部 |
LRANGE key start stop |
获取列表指定范围内的元素 |
RPOP key |
移除并获取列表最后一个元素 |
LLEN key |
获取列表长度 |
BRPOP key1 [key2] timeout |
移出并获取列表的最后一个元素 如果列表没有元素会阻塞列表直到等待超时或发现可弹出元素为止 |
集合(Set)常用命令
Redis set
是String
类型的无序集合。集合成员是唯一的,这就意味着集合中不能出现重复的数据
命令 |
描述 |
SADD key member1 [member2] |
向集合添加一个或多个成员 |
SMEMBERS key |
返回集合中的所有成员 |
SCARD key |
获取集合的成员数 |
SINTER key1 [key2] |
返回给定所有集合的交集 |
SUNION key1 [key2] |
返回所有给定集合的并集 |
SDIFF key1 [key2] |
返回给定所有集合的差集 |
SREM key member1 [member2] |
移除集合中一个或多个成员 |
有序集合(Sorted Set)常用命令
Redis Sorted Set
有序集合是String
类型元素的集合,且不允许重复的成员。每个元素都会关联一个double
类型的分数(score
) 。Redis
正是通过分数来为集合中的成员进行从小到大排序。有序集合的成员是唯一的,但分数却可以重复。
命令 |
描述 |
ZADD key score1 member1 [score2 member2] |
向有序集合添加一个或多个成员,或者更新已存在成员的分数 |
ZRANGE key start stop [WITHSCORES] |
通过索引区间返回有序集合中指定区间内的成员 |
ZINCRBY key increment member |
有序集合中对指定成员的分数加上增量increment |
ZREM key member [member …] |
移除有序集合中的一个或多个成员 |
通用命令
命令 |
描述 |
KEYs pattern |
查找所有符合给定模式(pattern)的key |
EXISTs key |
检查给定key是否存在 |
TYPE key |
返回key所储存的值的类型 |
TTL key |
返回给定key的剩余生存时间(TTL, time to live),以秒为单位 |
DEL key |
该命令用于在key存在是删除key |
在Java中使用Redis
简介
- Redis的Java客户端有很多,官方推荐的有三种
- Spring对Redis客户端进行了整合,提供了SpringDataRedis,在Spring Boot项目中还提供了对应的Starter,即
spring-boot-starter-data-redis
Jedis
- 使用Jedis的步骤
- 获取连接
- 执行操作
- 关闭连接
- 在此之前我们需要导入一下Jedis的maven坐标
1 2 3 4 5
| <dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.8.0</version> </dependency>
|
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
| @SpringBootTest class RedisTestApplicationTests {
@Test void contextLoads() { Jedis jedis = new Jedis("localhost", 6379); jedis.set("name", "Hades");
jedis.hset("stu", "name", "Jerry"); jedis.hset("stu", "age", "18"); jedis.hset("stu", "num", "4204000400");
Map<String, String> map = jedis.hgetAll("stu"); Set<String> keySet = map.keySet(); for (String key : keySet) { String value = map.get(key); System.out.println(key + ":" + value); } String name = jedis.get("name"); System.out.println(name); jedis.close(); }
}
|
num:4204000400
name:Jerry
age:18
Hades
- Jedis我们了解一下即可,大多数情况下我们还是用SpringDataRedis的
Spring Data Redis
-
SpringBoot项目中,可以使用SpringDataRedis来简化Redis(常用)
-
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,针对jedis客户端中大量api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:简单K-V操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:针对map类型的数据操作
- ListOperations:针对list类型的数据操作
-
使用SpringDataRedis,我们首先需要导入它的maven坐标
1 2 3 4 5
| <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency>
|
- 之后重新设置一下序列化器,防止出现乱码,在config包下创建
RedisConfig
配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Configuration public class RedisConfig extends CachingConfigurerSupport { @Bean public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
RedisTemplate<Object, Object> redisTemplate = new RedisTemplate<>();
redisTemplate.setKeySerializer(new StringRedisSerializer()); redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setConnectionFactory(connectionFactory);
return redisTemplate; } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13
| spring: redis: host: localhost port: 6379 database: 0 jedis: pool: max-active: 8 max-wait: 1ms max-idle: 4 min-idle: 0
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Test void stringTest() { ValueOperations valueOperations = redisTemplate.opsForValue(); valueOperations.set("name","Hades"); String name = (String) valueOperations.get("name"); System.out.println(name); valueOperations.set("age", "9527", 10, TimeUnit.SECONDS); String age = (String) valueOperations.get("age"); System.out.println(age); Boolean aBoolean = valueOperations.setIfAbsent("name", "Kyle"); System.out.println(aBoolean); }
|
输出结果如下,由于name已经存在,故Kyle设置失败,最后返回false,10秒过后,我们再去redis中get name,则输出nil
,表示不存在
Hades
9527
false
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
| @Test void hashTest() { HashOperations hashOperations = redisTemplate.opsForHash(); hashOperations.put("4204000400", "name", "Hades"); hashOperations.put("4204000400", "age", "18"); hashOperations.put("4204000400", "hobby", "Apex"); Map<String, String> map = hashOperations.entries("4204000400"); Set<String> keySet = map.keySet(); for (String hashKey : keySet) { System.out.println(hashKey + ":" + map.get(hashKey)); } System.out.println("$$$$$$$$$$$$$$$"); Set<String> keys = hashOperations.keys("4204000400"); for (String key : keys) { System.out.println(key); } System.out.println("$$$$$$$$$$$$$$$"); List<String> values = hashOperations.values("4204000400"); for (String value : values) { System.out.println(value); } }
|
输出结果如下
name:Hades
age:18
hobby:Apex
$$$$$$$$$$$$$$$
name
age
hobby
$$$$$$$$$$$$$$$
Hades
18
Apex
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| @Test void listTest() { ListOperations listOperations = redisTemplate.opsForList(); listOperations.leftPush("testData", "A"); listOperations.leftPushAll("testData", "B", "C", "D"); List<String> testDatas = listOperations.range("testData", 0, -1); for (String tableData : testDatas) { System.out.print(tableData + " "); } System.out.println(); Long size = listOperations.size("testData"); int value = size.intValue(); for (int i = 0; i < value; i++) { System.out.print(listOperations.leftPop("testData") + " "); } System.out.println(); System.out.println(listOperations.size("testData")); }
|
输出结果如下
D C B A
D C B A
0
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| @Test void setTest() { SetOperations setOperations = redisTemplate.opsForSet(); setOperations.add("tmp", "a", "b", "c", "d", "a"); 遍历输出 Set<String> tmpData = setOperations.members("tmp"); for (String value : tmpData) { System.out.print(value + " "); } System.out.println(); System.out.println("$$$$$$$$$$$$$$$$$$$"); setOperations.remove("tmp", "b", "c"); tmpData = setOperations.members("tmp"); for (String value : tmpData) { System.out.print(value + " "); } }
|
输出结果如下,符合预期
d b c a
$$$$$$$$$$$$$$$$$$$
d a
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
| @Test void zsetTest() { ZSetOperations zSetOperations = redisTemplate.opsForZSet(); zSetOperations.add("myZset", "a", 0.0); zSetOperations.add("myZset", "b", 1.0); zSetOperations.add("myZset", "c", 2.0); zSetOperations.add("myZset", "a", 3.0); Set<String> myZset = zSetOperations.range("myZset", 0, -1); for (String s : myZset) { System.out.println(s); } zSetOperations.incrementScore("myZset", "b", 4.0); System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"); myZset = zSetOperations.range("myZset", 0, -1); for (String s : myZset) { System.out.println(s); } zSetOperations.remove("myZset", "a", "b"); System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"); myZset = zSetOperations.range("myZset", 0, -1); for (String s : myZset) { System.out.println(s); } }
|
输出结果如下
b
c
a
$$$$$$$$$$$$$$$$$$$$$$$$$
c
a
b
$$$$$$$$$$$$$$$$$$$$$$$$$
c
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| @Test void commonTest() { Set<String> keys = redisTemplate.keys("*"); for (String key : keys) { System.out.println(key); } System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"); System.out.println(redisTemplate.hasKey("Random")); System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"); redisTemplate.delete("myZset"); keys = redisTemplate.keys("*"); for (String key : keys) { System.out.println(key); } System.out.println("$$$$$$$$$$$$$$$$$$$$$$$$$"); System.out.println(redisTemplate.type("tmp")); }
|
输出结果如下
tmp
name
4204000400
stu
myData
$$$$$$$$$$$$$$$$$$$$$$$$$
false
$$$$$$$$$$$$$$$$$$$$$$$$$
tmp
name
4204000400
stu
myData
$$$$$$$$$$$$$$$$$$$$$$$$$
SET