文章目录
一、Redis环境准备?
Redis是一个基于内存 的key-value结构数据库。Redis 是互联网技术领域使用最为广泛的存储中间件 。
官网: link
中文网:link
主要特点:基于内存存储,读写性能高
- 适合存储热点数据(热点商品、资讯、新闻)
- 企业应用广泛
Redis是用C语言开发的一个开源的高性能键值对(key-value)数据库,官方提供的数据是可以达到100000+的QPS(每秒内查询次数)。它存储的value类型比较丰富,也被称为结构化的NoSql数据库。
NoSql(Not Only SQL),不仅仅是SQL,泛指非关系型数据库。NoSql数据库并不是要取代关系型数据库,而是关系型数据库的补充。
下载与安装
下载:
Redis安装包分为windows版和Linux版:
- Windows版下载地址:https://github.com/microsoftarchive/redis/releases
- Linux版下载地址:
https://download.redis.io/releases/
安装:
在Windows中安装Redis
目录结构如下:
服务启动与停止
以window版Redis进行演示:
服务启动命令:redis-server.exe redis.windows.conf
Redis服务默认端口号为 6379 ,通过快捷键Ctrl + C 即可停止Redis服务
当Redis服务启动成功后,可通过客户端进行连接。
客户端连接命令
在redis安装目录中,执行命令为:redis-cli.exe
,如下图
通过redis-cli.exe命令默认连接的是本地的redis服务,并且使用默认6379端口。也可以通过指定如下参数连接:
- -h ip地址
- -p 端口号
- -a 密码(如果需要)
Redis配置文件
在根目录中的redis.windows.conf文件为redis的核心配置文件,可根据项目情况设置不同的参数 在第443行
-
设置Redis服务密码,添加内容为:
requirepass 123456
设置密码为123456
注意: -
修改密码后需要重启Redis服务才能生效
-
Redis配置文件中 # 表示注释
重启Redis后,再次连接Redis时,需加上密码,否则连接失败。
加上秘密后的命令如下:
redis-cli.exe -a 123456
如果是远程的redis服务,也可以使用以下命令指定ip和端口
redis-cli.exe -h localhost -p 6379 -a 123456
客户端图形工具
默认提供的客户端连接工具界面不太友好,同时操作也较为麻烦,接下来,引入一个Redis客户端图形工具。
成功之后,可以直接查看redis中存储的数据
二、Redis数据类型及命令
Redis存储的是key-value结构的数据,其中key是字符串类型,value有5种常用的数据类型:
字符串操作命令
Redis 中字符串类型常用命令:
SET key value | 设置指定key的值 |
---|---|
GET key | 获取指定key的值 |
SETEX key seconds value | 设置指定key的值,并将 key 的过期时间设为 seconds 秒 |
SETNX key value | 只有在 key 不存在时设置 key 的值 |
- set key(同一个key),后执行的会覆盖之前的数据
- del key 删除key的数据,这个是通用的命令,不仅仅只是在字符串中适用
- setnx与set在存储数据的时候,set可以覆盖之前的数据,sexnx则不行
java
127.0.0.1:6379> set name lisi
OK
127.0.0.1:6379> get name
"lisi"
127.0.0.1:6379> setex age 10 20 # key为20,10为过期时间(秒),20为值
OK
127.0.0.1:6379> get age
"20"
127.0.0.1:6379> setnx age 40
(integer) 0 #设置失败,age存在则保存不成功
127.0.0.1:6379> setnx city beijing
(integer) 1 #设置成功
哈希操作命令
Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。
Redis hash 是一个string类型的 field 和 value 的映射表,hash特别适合用于存储对象,常用命令:
HSET key field value | 将哈希表 key 中的字段 field 的值设为 value |
---|---|
HGET key field | 获取存储在哈希表中指定字段的值 |
HDEL key field | 删除存储在哈希表中的指定字段 |
HKEYS key | 获取哈希表中所有字段 |
HVALS key | 获取哈希表中所有值 |
数据特点:
java
127.0.0.1:6379> hset heima name zhangsan
(integer) 1
127.0.0.1:6379> hget heima name
"zhangsan"
127.0.0.1:6379> hdel heima name
(integer) 1
127.0.0.1:6379> hget heima name
(nil)
127.0.0.1:6379> hset heima name zhangsan
(integer) 1
127.0.0.1:6379> hkeys heima
1) "name"
127.0.0.1:6379> hset heima age 30
(integer) 1
127.0.0.1:6379> hvals heima
1) "zhangsan"
2) "30"
列表操作命令
Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。
特征也与LinkedList类似:
- 有序
- 元素可以重复
- 插入和删除快
- 查询速度一般
常用命令:
LPUSH key value1 [value2] | 将一个或多个值插入到列表头部 |
---|---|
LRANGE key start stop | 获取列表指定范围内的元素 |
RPOP key | 移除并获取列表最后一个元素 |
LLEN key | 获取列表长度 |
BRPOP key1 [key2 ] timeout | 移出并获取列表的最后一个元素, 如果列表没有元素会阻塞列表直到等待超 时或发现可弹出元素为止 |
java
127.0.0.1:6379> lpush list a b c
(integer) 3
127.0.0.1:6379> llen list
(integer) 3
127.0.0.1:6379> lrange list 0 1
1) "c"
2) "b"
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> rpop list
"a"
127.0.0.1:6379> lrange list 0 -1
1) "c"
2) "b"
127.0.0.1:6379> lpop list
"c"
127.0.0.1:6379> lrange list 0 -1
1) "b"
127.0.0.1:6379> brpop list 10
1) "list"
2) "b"
127.0.0.1:6379> lrange list 0 -1
(empty list or set)
集合操作命令
Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:
- 无序
- 元素不可重复
- 查找快
- 支持交集、并集、差集等功能
常见命令:
SADD key member1 [member2] | 向集合添加一个或多个成员 |
---|---|
SMEMBERS key | 返回集合中的所有成员 |
SCARD key | 获取集合的成员数 |
SINTER key1 [key2] | 返回给定所有集合的交集 |
SUNION key1 [key2] | 返回所有给定集合的并集 |
SREM key member1 [member2] | 移除集合中一个或多个成员 |
java
127.0.0.1:6379> sadd set a b c d a
(integer) 4
127.0.0.1:6379> smembers set
1) "c"
2) "a"
3) "d"
4) "b"
127.0.0.1:6379> scard set
(integer) 4
127.0.0.1:6379> sadd set2 a e f
(integer) 3
127.0.0.1:6379> sinter set set2
1) "a"
127.0.0.1:6379> sunion set set2
1) "b"
2) "c"
3) "f"
4) "e"
5) "a"
6) "d"
127.0.0.1:6379> srem set a
(integer) 1
127.0.0.1:6379> smembers set
1) "c"
2) "b"
3) "d"
127.0.0.1:6379>
有序集合操作命令
Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。
SortedSet具备下列特性:
- 可排序
- 元素不重复
- 查询速度快
因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。
常用命令:
ZADD key score1 member1 [score2 member2] | 向有序集合添加一个或多个成员 |
---|---|
ZRANGE key start stop [WITHSCORES] | 通过索引区间返回有序集合中指定区间内的成员 |
ZINCRBY key increment member | 有序集合中对指定成员的分数加上增量 increment |
ZREM key member [member ...] | 移除有序集合中的一个或多个成员 |
java
127.0.0.1:6379> zadd zset 10 heima
(integer) 1
127.0.0.1:6379> zadd zset 10 heima 20 itcast
(integer) 1
127.0.0.1:6379> zrange zset 0 20
1) "heima"
2) "itcast"
127.0.0.1:6379> zincrby zset 30 heima
"40"
127.0.0.1:6379> zincrby zset 50 heima
"90"
127.0.0.1:6379> zrange zset 0 -1 withscores
1) "itcast"
2) "20"
3) "heima"
4) "90"
通用命令
Redis的通用命令是不分数据类型的,都可以使用的命令:
KEYS pattern | 查找所有符合给定模式( pattern)的 key |
---|---|
EXISTS key | 检查给定 key 是否存在 |
TYPE key | 返回 key 所储存的值的类型 |
DEL key | 该命令用于在 key 存在是删除 key |
java
127.0.0.1:6379> keys *
1) "RECORD:355"
2) "city"
3) "RECORD:351"
4) "name"
5) "RECORD:340"
6) "RECORD:348"
7) "RECORD:346"
8) "zset"
9) "RECORD:345"
10) "RECORD:343"
11) "set2"
12) "heima"
13) "set"
14) "RECORD:350"
15) "age"
16) "zset2"
127.0.0.1:6379> exists heima
(integer) 1
127.0.0.1:6379> exists heima2
(integer) 0
127.0.0.1:6379> type heima
hash
127.0.0.1:6379> del heima
(integer) 1
127.0.0.1:6379> exeits heima
(error) ERR unknown command 'exeits'
三、Redis持久化
Redis有两种持久化方案:
- RDB持久化
- AOF持久化
RDB持久化(默认)
RDB全称Redis Database Backup file(Redis数据备份文件),也被叫做Redis数据快照。简单来说就是把内存中的所有数据都记录到磁盘中。当Redis实例故障重启后,从磁盘读取快照文件,恢复数据。快照文件称为RDB文件,默认是保存在当前运行目录。
执行时机:
RDB持久化在四种情况下会执行:
- 执行save命令
- 执行bgsave命令 background
- Redis停机时(shutdown命令关机)
- 触发RDB条件时
AOF持久化
AOF全称为Append Only File(追加文件)。Redis处理的每一个写命令都会记录在AOF文件,可以看做是命令日志文件。
AOF默认是关闭的,需要修改redis.conf配置文件来开启AOF:
properties
# 是否开启AOF功能,默认是no 581行
appendonly yes
AOF的命令记录的频率也可以通过redis.conf文件来配:
properties
# 表示每执行一次写命令,立即记录到AOF文件 609行
appendfsync always
# 写命令执行完先放入AOF缓冲区,然后表示每隔1秒将缓冲区数据写到AOF文件,是默认方案
appendfsync everysec
# 写命令执行完先放入AOF缓冲区,由操作系统决定何时将缓冲区内容写回磁盘
appendfsync no
RDB和AOF各有自己的优缺点,如果对数据安全性要求较高,在实际开发中往往会结合两者来使用。
四、Java中操作Redis
Spring Data Redis
Spring Data Redis 是 Spring 的一部分,提供了在 Spring 应用中通过简单的配置就可以访问 Redis 服务,对 Redis 底层开发包进行了高度封装。在 Spring 项目中,可以使用Spring Data Redis来简化 Redis 操作。
网址:https://spring.io/projects/spring-data-redis
Spring Boot提供了对应的Starter,maven坐标:
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
Spring Data Redis中提供了一个高度封装的类:RedisTemplate,对相关api进行了归类封装,将同一类型操作封装为operation接口,具体分类如下:
- ValueOperations:string数据操作
- SetOperations:set类型数据操作
- ZSetOperations:zset类型数据操作
- HashOperations:hash类型的数据操作
- ListOperations:list类型的数据操作
环境搭建
在application.yml文件,配置redis连接,如下:
spring:
redis:
host: localhost
port: 6379
password: 123456
操作常见类型数据
java
@SpringBootTest(classes = CacheDemoApplication.class)
@RunWith(SpringRunner.class)
public class RedisTest {
@Autowired
private RedisTemplate<String,String> redisTemplate;
@Test
public void test(){
System.out.println(redisTemplate);
}
}
上述代码中直接注入了RedisTemplate,并且指定了泛型为String
- 如果不指定泛型也可以进行操作,但是存储对象的时候需要进行序列化
- 一般项目中存储对象都会先转换为json字符串,再进行存储,所以一般会选择使用泛型为String,避免大量的序列化操作
操作字符串数据类型
java
/**
* 操作字符串类型的数据
*/
@Test
public void testString(){
// 普通的放入数据
// redisTemplate.boundValueOps("name").set("zhangsan");
// 设置超时时间
// redisTemplate.boundValueOps("name1").set("lisi",10, TimeUnit.SECONDS);
// 分布式锁的原理
// Boolean aBoolean1 = redisTemplate.boundValueOps("name2").setIfAbsent("wangwu");
// System.out.println(aBoolean1);
// Boolean aBoolean2 = redisTemplate.boundValueOps("name2").setIfAbsent("wangwu");
// System.out.println(aBoolean2);
// 获取数据
String name = redisTemplate.boundValueOps("name").get();
System.out.println(name);
}
操作哈希类型数据
java
/**
* 操作哈希类型的数据
*/
@Test
public void testHash(){
// BoundHashOperations<String, String, String> boundHashOps = redisTemplate.boundHashOps("math");
//
// boundHashOps.put("zhangsan","100");
// boundHashOps.put("lisi","99");
// boundHashOps.put("wangwu","90");
// boundHashOps.put("zhaoliu","95");
//
// BoundHashOperations<String, String, String> boundHashOps1 = redisTemplate.boundHashOps("chinese");
//
// boundHashOps1.put("zhangsan","89");
// boundHashOps1.put("lisi","76");
// boundHashOps1.put("wangwu","78");
// boundHashOps1.put("zhaoliu","99");
BoundHashOperations<String, String, String> boundHashOps = redisTemplate.boundHashOps("math");
//删除某一对数据
Long zhangsan1 = boundHashOps.delete("zhangsan");
//获取大key中的所有数据
Map<String, String> map = boundHashOps.entries();
for (Map.Entry<String, String> entry : map.entrySet()) {
System.out.println(entry.getKey()+"--->"+entry.getValue());
}
//获取指定小key的数据
String zhangsan = boundHashOps.get("zhangsan");
System.out.println(zhangsan);
}
操作列表类型数据
java
/**
* 操作列表类型的数据
*/
@Test
public void testList(){
// 有顺序
BoundListOperations<String, String> listOperations = redisTemplate.boundListOps("listKey");
// listOperations.leftPush("A"); //A
// listOperations.leftPush("B"); //BA
// listOperations.leftPush("C"); //CBA
// listOperations.leftPush("D"); //DCBA
// // 普通的取数据
// List<String> range = listOperations.range(0, 3);
// System.out.println(range);
// 弹出式的获取 秒杀商品数量的记录
// String s = listOperations.rightPop();
// System.out.println(s);
BoundListOperations<String, String> goodsOperations = redisTemplate.boundListOps("iphone16");
// for (int i = 0; i < 10; i++) {
// goodsOperations.leftPush("iphone16Id");
// }
for (int i = 0; i < 10; i++) {
goodsOperations.rightPop();
}
String s = goodsOperations.rightPop();
System.out.println( s);
}
操作集合类型数据
java
/**
* 操作集合类型的数据
*/
@Test
public void testSet(){
BoundSetOperations<String, String> setOps = redisTemplate.boundSetOps("setKey");
setOps.add("A");
setOps.add("B");
setOps.add("C");
setOps.add("D");
setOps.add("B");
setOps.add("A");
Set<String> members = setOps.members();
System.out.println(members);
}
操作有序集合类型数据
java
/**
* 操作有序集合类型的数据
*/
@Test
public void testZset(){
BoundZSetOperations<String, String> zSetOps = redisTemplate.boundZSetOps("zsetKey");
// zSetOps.add("zhangsan",100);
// zSetOps.add("lisi",88);
// zSetOps.add("wangwu",99);
// zSetOps.add("zhaoliu",109);
// Set<String> range = zSetOps.range(0, 3); //默认升序 lisi wangwu zhangsan zhaoliu
// System.out.println(range);
// 排名 rank 反向排名 reverseRank
Long zhangsanRank = zSetOps.reverseRank("zhangsan");
System.out.println(zhangsanRank);
// Set<String> range1 = zSetOps.reverseRange(0, 3); //默认升序 zhaoliu zhangsan wangwu lisi
// System.out.println(range1);
}
通用命令操作
java
/**
* 通用命令操作
*/
@Test
public void testCommon(){
//keys exists type del
Set keys = redisTemplate.keys("*");
System.out.println(keys);
Boolean name = redisTemplate.hasKey("name");
Boolean set1 = redisTemplate.hasKey("set1");
for (Object key : keys) {
DataType type = redisTemplate.type((String) key);
System.out.println(type.name());
}
redisTemplate.delete("mylist");
}