Redis初步学习

简单了解

Redis(Remote Dictionary Server)是一个开源的内存数据库,也被称为数据结构服务器。它以键值对的形式存储数据,并提供了丰富的数据结构,如字符串、列表、集合、有序集合、哈希表等。以下是对Redis的详细介绍:

1. 内存数据库: Redis是一个基于内存的数据库,所有数据都存储在内存中,这使得它具有非常快的读写速度。同时,Redis也支持将数据持久化到磁盘,以防止数据丢失。

2. 键值存储: Redis的数据模型是简单的键值对(key-value),其中每个键都与一个值相关联。这些值可以是各种数据类型,如字符串、整数、列表、集合等。

3. 数据结构支持: Redis提供了丰富的数据结构支持,包括:

  • 字符串(String):用于存储文本或二进制数据。
  • 列表(List):有序的字符串列表,支持插入、删除、修剪等操作。
  • 集合(Set):无序的唯一值集合,支持交集、并集、差集等操作。
  • 有序集合(Sorted Set):有序的唯一值集合,每个值都关联了一个分数,可以根据分数排序。
  • 哈希表(Hash):类似于关联数组,可以用于存储多个字段和值。

4. 高性能: Redis具有非常高的读写性能,因为数据存储在内存中,并且采用了单线程模型来处理请求。这使得它成为了处理大规模数据的理想选择。

5. 持久化: Redis支持将数据持久化到磁盘,以防止数据丢失。它提供了两种持久化方式:快照(snapshot)和追加文件(append-only file)。快照方式会定期将数据保存到磁盘,而追加文件方式则会将每个写操作追加到日志文件中。

6. 发布订阅(Pub/Sub): Redis支持发布-订阅模式,允许客户端订阅一个或多个频道,并在消息被发布到频道时接收通知。

7. 事务支持: Redis支持事务操作,可以一次性执行多个命令,并确保这些命令要么全部执行成功,要么全部失败。

8. Lua脚本: Redis允许用户使用Lua脚本来执行一系列命令,这使得可以在服务器端执行复杂的操作。

9. 分布式: Redis提供了一些分布式特性,可以用于构建高可用性的分布式系统,包括主从复制、哨兵模式和集群模式。

10. 应用场景: Redis在许多领域都有广泛的应用,包括缓存、会话存储、实时排行榜、消息队列、计数器、地理位置数据存储等。

总之,Redis是一个强大且多才多艺的内存数据库,适用于各种不同类型的应用程序。它的简单性、高性能和丰富的数据结构支持使得它成为了许多开发人员和企业的首选数据库之一。

本文主要基于黑马的redis视频 编写(2022年的)

Redis是一种键值型的NoSql数据库,这里有两个关键字:

  • 键值型
  • NoSql

其中键值型,是指Redis中存储的数据都是以key.value对的形式存储,而value的形式多种多样,可以是字符串.数值.甚至json:

redis入门

NoSQL

NoSql可以翻译做Not Only Sql(不仅仅是SQL),或者是No Sql(非Sql的)数据库。是相对于传统关系型数据库而言,有很大差异的一种特殊的数据库,因此也称之为非关系型数据库

  • 与关系型数据库对比

传统关系型数据库是结构化数据,每一张表都有严格的约束信息:字段名.字段数据类型.字段约束等等信息,插入的数据必须遵守这些约束:

而NoSql则对数据库格式没有严格约束,往往形式松散,自由。可以是键值型;文档型;图格式

传统数据库的表与表之间往往存在关联,例如外键

而非关系型数据库不存在关联关系,要维护关系要么靠代码中的业务逻辑,要么靠数据之间的耦合

传统关系型数据库会基于Sql语句做查询,语法有统一标准;

而不同的非关系数据库查询语法差异极大,五花八门各种各样。

传统关系型数据库能满足事务ACID的原则

而非关系型数据库往往不支持事务,或者不能严格保证ACID的特性,只能实现基本的一致性。

  • 存储方式
    • 关系型数据库基于磁盘进行存储,会有大量的磁盘IO,对性能有一定影响
    • 非关系型数据库,他们的操作更多的是依赖于内存来操作,内存的读写速度会非常快,性能自然会好一些
  • 扩展性
    • 关系型数据库集群模式一般是主从,主从数据一致,起到数据备份的作用,称为垂直扩展。
    • 非关系型数据库可以将数据拆分,存储在不同机器上,可以保存海量数据,解决内存大小有限的问题。称为水平扩展。
    • 关系型数据库因为表之间存在关联关系,如果做水平扩展会给数据查询带来很多麻烦

Redis

Redis全称是Remote Dictionary Server 远程词典服务器,是一个基于内存的键值型NoSQL数据库。

特征

  • 键值(key-value)型,value支持多种不同数据结构,功能丰富
  • 单线程,每个命令具备原子性
  • 低延迟,速度快(基于内存.IO多路复用.良好的编码)。
  • 支持数据持久化
  • 支持主从集群.分片集群
  • 支持多语言客户端

Redis安装

通过Docker安装

docker search redis
docker pul redis
docker run --restart=always -p 6379:6379 --name myredis -v /home/redis/myredis/myredis.conf:/etc/redis/redis.conf -v /home/redis/myredis/data:/data -d redis redis-server /etc/redis/redis.conf  --appendonly yes

docker exec -it <容器名> /bin/bash

Redis常见命令

Redis数据结构介绍

Redis是一个key-value的数据库,key一般是String类型,不过value的类型多种多样:

image-20230806154902437

Redis 通用命令

通用指令是部分数据类型的,都可以使用的指令,常见的有:

  • KEYS:查看符合模板的所有key
127.0.0.1:6379> keys *

# 查询以a开头的key
127.0.0.1:6379> keys a*
1) "age"

在生产环境下,不推荐使用keys 命令,因为这个命令在key过多的情况下,效率不高

  • DEL:删除一个指定的key
127.0.0.1:6379> del name #删除单个
(integer) 1  #成功删除1个

127.0.0.1:6379> keys *
1) "age"

127.0.0.1:6379> MSET k1 v1 k2 v2 k3 v3 #批量添加数据
OK

127.0.0.1:6379> keys *
1) "k3"
2) "k2"
3) "k1"
4) "age"

127.0.0.1:6379> del k1 k2 k3 k4
(integer) 3   #此处返回的是成功删除的key,由于redis中只有k1,k2,k3 所以只成功删除3个,最终返回

127.0.0.1:6379> keys * #再查询全部的key
1) "age"	#只剩下一个了
  • EXISTS:判断key是否存在
127.0.0.1:6379> exists age
(integer) 1

127.0.0.1:6379> exists name
(integer) 0
  • EXPIRE:给一个key设置有效期,有效期到期时该key会被自动删除
  • TTL:查看一个KEY的剩余有效期
127.0.0.1:6379> expire age 10
(integer) 1

127.0.0.1:6379> ttl age
(integer) 8

127.0.0.1:6379> ttl age
(integer) -2

127.0.0.1:6379> ttl age
(integer) -2  #当这个key过期了,那么此时查询出来就是-2 

127.0.0.1:6379> keys *
(empty list or set)

127.0.0.1:6379> set age 10 #如果没有设置过期时间
OK

127.0.0.1:6379> ttl age
(integer) -1  # ttl的返回值就是-1

Redis命令-String命令

String类型,也就是字符串类型,是Redis中最简单的存储类型。

其value是字符串,不过根据字符串的格式不同,又可以分为3类:

  • string:普通字符串
  • int:整数类型,可以做自增.自减操作
  • float:浮点类型,可以做自增.自减操作

String的常见命令有:

  • SET:添加或者修改已经存在的一个String类型的键值对
  • GET:根据key获取String类型的value
  • MSET:批量添加多个String类型的键值对
  • MGET:根据多个key获取多个String类型的value
  • INCR:让一个整型的key自增1
  • INCRBY:让一个整型的key自增并指定步长,例如:incrby num 2 让num值自增2
  • INCRBYFLOAT:让一个浮点类型的数字自增并指定步长
  • SETNX:添加一个String类型的键值对,前提是这个key不存在,否则不执行
  • SETEX:添加一个String类型的键值对,并且指定有效期

Redis命令-Key的层级结构

Redis没有类似MySQL中的Table的概念,我们该如何区分不同类型的key呢?

Redis的key允许有多个单词形成层级结构,多个单词之间用':'隔开

这个格式并非固定,也可以根据自己的需求来删除或添加词条。

例如我们的项目名称叫 heima,有user和product两种不同类型的数据,我们可以这样定义key:

  • user相关的key:heima:user:1

  • product相关的key:heima:product:1

如果Value是一个Java对象,例如一个User对象,则可以将对象序列化为JSON字符串后存储:

KEY VALUE
heima:user:1
heima:product:1

一旦我们向redis采用这样的方式存储,那么在可视化界面中,redis会以层级结构来进行存储,更加方便Redis获取数据

Redis命令-Hash命令

Hash类型,也叫散列,其value是一个无序字典,类似于Java中的HashMap结构。

String结构是将对象序列化为JSON字符串后存储,当需要修改对象某个字段时很不方便:

Hash结构可以将对象中的每个字段独立存储,可以针对单个字段做CRUD:

Hash类型的常见命令

  • HSET key field value:添加或者修改hash类型key的field的值

  • HGET key field:获取一个hash类型key的field的值

  • HMSET:批量添加多个hash类型key的field的值

  • HMGET:批量获取多个hash类型key的field的值

  • HGETALL:获取一个hash类型的key中的所有的field和value

  • HKEYS:获取一个hash类型的key中的所有的field

  • HINCRBY:让一个hash类型key的字段值自增并指定步长

  • HSETNX:添加一个hash类型的key的field值,前提是这个field不存在,否则不执行

Redis命令-List命令

Redis中的List类型与Java中的LinkedList类似,可以看做是一个双向链表结构。既可以支持正向检索和也可以支持反向检索。

特征也与LinkedList类似:

  • 有序
  • 元素可以重复
  • 插入和删除快
  • 查询速度一般

常用来存储一个有序数据,例如:朋友圈点赞列表,评论列表等。

List的常见命令有:

  • LPUSH key element ... :向列表左侧插入一个或多个元素
  • LPOP key:移除并返回列表左侧的第一个元素,没有则返回nil
  • RPUSH key element ... :向列表右侧插入一个或多个元素
  • RPOP key:移除并返回列表右侧的第一个元素
  • LRANGE key star end:返回一段角标范围内的所有元素
  • BLPOP和BRPOP:与LPOP和RPOP类似,只不过在没有元素时等待指定时间,而不是直接返回nil

Redis命令-Set命令

Redis的Set结构与Java中的HashSet类似,可以看做是一个value为null的HashMap。因为也是一个hash表,因此具备与HashSet类似的特征:

  • 无序
  • 元素不可重复
  • 查找快
  • 支持交集.并集.差集等功能

Set类型的常见命令

  • SADD key member ... :向set中添加一个或多个元素
  • SREM key member ... : 移除set中的指定元素
  • SCARD key: 返回set中元素的个数
  • SISMEMBER key member:判断一个元素是否存在于set中
  • SMEMBERS:获取set中的所有元素
  • SINTER key1 key2 ... :求key1与key2的交集
  • SDIFF key1 key2 ... :求key1与key2的差集
  • SUNION key1 key2 ..:求key1和key2的并集

redis命令-SortedSet类型

Redis的SortedSet是一个可排序的set集合,与Java中的TreeSet有些类似,但底层数据结构却差别很大。SortedSet中的每一个元素都带有一个score属性,可以基于score属性对元素排序,底层的实现是一个跳表(SkipList)加 hash表。

SortedSet具备下列特性:

  • 可排序
  • 元素不重复
  • 查询速度快

因为SortedSet的可排序特性,经常被用来实现排行榜这样的功能。

SortedSet的常见命令有:

  • ZADD key score member:添加一个或多个元素到sorted set ,如果已经存在则更新其score值
  • ZREM key member:删除sorted set中的一个指定元素
  • ZSCORE key member : 获取sorted set中的指定元素的score值
  • ZRANK key member:获取sorted set 中的指定元素的排名
  • ZCARD key:获取sorted set中的元素个数
  • ZCOUNT key min max:统计score值在给定范围内的所有元素的个数
  • ZINCRBY key increment member:让sorted set中的指定元素自增,步长为指定的increment值
  • ZRANGE key min max:按照score排序后,获取指定排名范围内的元素
  • ZRANGEBYSCORE key min max:按照score排序后,获取指定score范围内的元素
  • ZDIFF.ZINTER.ZUNION:求差集.交集.并集

注意:所有的排名默认都是升序,如果要降序则在命令的Z后面添加REV即可,例如:

  • 升序获取sorted set 中的指定元素的排名:ZRANK key member
  • 降序获取sorted set 中的指定元素的排名:ZREVRANK key memeber

Java客户端-Jedis(简单了解)

Jedis是一个流行的Java客户端库,用于与Redis数据库进行交互。它提供了一组丰富的API,使Java开发人员能够轻松地连接到Redis服务器并执行各种操作。以下是对Jedis的详细介绍:

1. 连接到Redis: Jedis允许你轻松地与Redis服务器建立连接。你可以通过指定Redis服务器的主机和端口来创建一个Jedis连接。例如:

Jedis jedis = new Jedis("localhost", 6379);

2. 数据操作: Jedis提供了一组方法来执行各种数据操作,包括:

  • 存储和获取字符串数据。
  • 存储和获取列表数据。
  • 存储和获取集合数据。
  • 存储和获取有序集合数据。
  • 存储和获取哈希表数据。

以下是一些常见的数据操作示例:

// 存储字符串数据
jedis.set("key", "value");

// 获取字符串数据
String value = jedis.get("key");

// 存储列表数据
jedis.lpush("mylist", "item1", "item2", "item3");

// 获取列表数据
List<String> myList = jedis.lrange("mylist", 0, -1);

3. 事务支持: Jedis支持事务操作,你可以通过multi()exec()方法来执行一系列命令,这些命令要么全部执行成功,要么全部失败。例如:

jedis.multi();
jedis.set("key1", "value1");
jedis.set("key2", "value2");
jedis.exec(); // 提交事务

4. 数据类型转换: Jedis支持将Java对象与Redis数据类型进行相互转换。你可以使用Jedis提供的方法将Java对象序列化为字符串,并将其存储在Redis中,然后再将其反序列化为Java对象。这对于存储和检索复杂数据结构非常有用。

5. 发布-订阅模式: Jedis支持Redis的发布-订阅模式,允许你创建发布者和订阅者,以便实现实时消息传递和事件通知。

6. 连接池支持: Jedis提供了连接池功能,可以重复使用连接以提高性能,并在需要时自动创建新连接。

7. 异常处理: Jedis具有良好的异常处理机制,可以捕获和处理与Redis服务器的连接问题、命令执行错误等异常情况。

8. 高性能: Jedis是一个高性能的Redis客户端,它通过池化、异步执行等方式来优化性能。

9. 社区活跃: Jedis是一个活跃的开源项目,有大量的社区支持和贡献,因此它经常得到更新和改进。

总之,Jedis是一个强大的Java客户端库,用于与Redis数据库进行交互。它提供了丰富的功能和易用的API,使Java开发人员能够轻松地利用Redis的功能来构建各种类型的应用程序,包括缓存、会话存储、消息队列等。如果你正在使用Redis,并且使用Java开发应用程序,Jedis是一个非常有用的工具。

当使用Jedis与Redis进行交互时,你需要先引入Jedis库,然后创建一个Jedis客户端实例来连接到Redis服务器。以下是一个完整的示例,演示了如何使用Jedis执行一些常见的操作:

首先,确保你的项目中包含了Jedis库的依赖。如果你使用Maven,可以在pom.xml文件中添加以下依赖:

<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>3.7.0</version> <!-- 使用最新版本 -->
</dependency>

接下来,你可以编写Java代码来与Redis进行交互:

import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;

public class JedisExample {

    public static void main(String[] args) {
        // 创建连接池配置
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        poolConfig.setMaxTotal(10); // 最大连接数
        poolConfig.setMaxIdle(5);   // 最大空闲连接数

        // 创建连接池
        JedisPool jedisPool = new JedisPool(poolConfig, "localhost", 6379);

        // 获取Jedis实例
        try (Jedis jedis = jedisPool.getResource()) {
            // 执行一些基本操作
            jedis.set("name", "John");
            String name = jedis.get("name");
            System.out.println("Name: " + name);

            // 存储列表数据
            jedis.lpush("mylist", "item1", "item2", "item3");
            // 获取列表数据
            System.out.println("List: " + jedis.lrange("mylist", 0, -1));

            // 使用事务
            jedis.watch("key1"); // 监视键
            jedis.multi();       // 开启事务
            jedis.set("key1", "value1");
            jedis.set("key2", "value2");
            jedis.exec();        // 提交事务
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭连接池
            jedisPool.close();
        }
    }
}

上述示例中,我们首先创建了一个Jedis连接池,配置了最大连接数和最大空闲连接数。然后,我们获取一个Jedis实例,执行了一些基本的操作,如设置和获取字符串、存储和获取列表数据,以及使用事务。最后,我们在finally块中关闭了连接池。