跟着狂神学习的Redis笔记,详细课程可以移步【狂神说Java】Redis最新超详细版教程通俗易懂
文章目录
- NoSQL
- NoSQL 数据库的主要类型
- NoSQL 的特点
- NoSQL 的应用场景
- Redis
- 什么是 Redis
- Redis 能干嘛
- Windows 以及 Linux 下安装 Redis
- Redis 基本知识
- RedisKey的基本命令
- Redis 五大数据类型
- String
- List
- Set
- Hash
- Zset
- Redis 三种特殊数据类型
- geospatial
- hyperloglog
- bitmaps
NoSQL
- NoSQL(Not Only SQL)
- NoSQL(Not Only SQL)是一类数据库管理系统,设计用于处理非关系型数据。
- 与传统的关系型数据库(如MySQL、PostgreSQL)不同,NoSQL数据库不使用表格、行、列的结构,而是采用多种数据模型来处理大量的非结构化和半结构化数据。
- 这种灵活性使得NoSQL特别适合处理大规模、快速增长的数据集,尤其在现代Web应用、大数据和云计算环境中广泛应用。
NoSQL 数据库的主要类型
-
键值存储(Key-Value Store):数据以键值对的形式存储,键(key)是唯一的标识符,值(value)可以是任何类型的数据。例子:Redis, DynamoDB
-
文档数据库(Document Store):数据以文档的形式存储,通常使用JSON、BSON、XML等格式。这些文档是自包含的,每个文档可以拥有不同的结构。例子:MongoDB, CouchDB
-
列族存储(Column-Family Store):数据以列为中心进行存储和查询,而不是行。适用于读取和处理大规模的稀疏数据。例子:Apache Cassandra, HBase
-
图数据库(Graph Database):专门用于处理复杂关系数据,数据以节点、边和属性的形式存储,特别适合社交网络、推荐系统等场景。例子:Neo4j, Amazon Neptune
NoSQL 的特点
- 高扩展性:NoSQL数据库通常支持水平扩展,可以通过增加服务器节点来处理数据增长。
- 灵活的数据模型:与关系型数据库的固定表结构不同,NoSQL支持灵活的、动态的模式。
- 高性能:NoSQL擅长处理大规模并发读写操作,性能通常优于传统数据库。
- 可扩展的存储:适合处理海量数据,特别是在大数据和实时数据分析中。
NoSQL 的应用场景
- 大数据处理:如社交媒体数据、物联网数据、日志分析。
- 实时Web应用:例如聊天应用、游戏应用、在线购物平台。
- 分布式数据存储:如内容管理系统、文档管理系统、用户配置文件管理等。
尽管NoSQL具备高性能和灵活性,但在事务处理和复杂查询方面,它不如传统的关系型数据库,因此在选择数据库时需根据具体的业务需求进行权衡。
Redis
什么是 Redis
- Redis - Remote Dictionary Server 远程字典服务
基于内存、可持久化的日志型,Key-Value数据库,被人们称为结构化数据库。
redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了master-slave(主从)同步。
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件MQ。它支持多种类型的数据结构,如字符串(strings),散列(hashes),列表(lists),集合(sets),有序集合(sprted sets)与范围查询,bitmaps ,hyperloglogs和地理空间(geospatial)索引半径査询。 Redis 内置了复制(replication),LUA脚本(Luascripting),LRU驱动事件(LRU eviction),事务(transactions)和不同级别的 磁盘持久化(persistence),并通过 Redis哨兵(sentinel)和自动 分区(Cluster)提供高可用性(high availability)。
Redis 能干嘛
Redis 是一个开源的、基于内存的键值存储数据库,通常用于实现高性能的缓存、消息队列、会话管理等功能。它支持多种数据结构,适用于多种应用场景。
-
缓存:Redis 可以作为高效的缓存层,减少数据库查询次数,提升系统响应速度。常用于存储需要快速访问的数据,如网页内容、API 响应等。效率高、可以用于高速缓存, 内存存储,断电即失。
-
持久化:虽然 Redis 是内存数据库,但它也支持数据持久化。可以将内存中的数据定期或实时保存到磁盘,防止数据丢失。rdb、aof
-
分布式锁:Redis 提供了简单可靠的分布式锁机制,适用于多服务器环境中保证资源的独占访问。使用
SETNX
命令可以实现一个互斥锁。 -
消息队列:Redis 支持发布/订阅(pub/sub)机制,可以用来构建轻量级的消息队列系统,实现实时通信或事件通知。
-
会话管理:由于其速度快,Redis 常用于存储用户会话信息,特别是在需要分布式存储的应用中。
-
数据结构:Redis 不仅支持简单的键值对,还支持丰富的数据结构,比如字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(sorted set)等。这些数据结构的多样性使 Redis 能处理复杂的数据操作,比如计数器、排行榜、推荐系统等。
-
分布式系统支持:Redis 具有集群模式,可以扩展到多节点分布式系统,支持高可用性和水平扩展。
-
地理空间查询:Redis 提供了 GEO 类型,允许存储、查询地理位置数据,支持以半径搜索附近地点等地理空间操作。
Windows 以及 Linux 下安装 Redis
- Github地址
- 官网
- 下载安装包后解压到本地,双击运行服务即可。
- Redis的默认端口:6379
- Windows下使用确实简单,但是Redis更推荐使用Linux去开发使用
ping //测试连接,如果成功会返回 pong
set name erizj //设置kv基本的值,返回ok
get name //获取值,返回erizj
Redis 基本知识
127.0.0.1:6379> select 3 #切换数据库
OK
127.0.0.1:6379> DBSIZE #查看DB大小!
(integer) 0
127.0.0.1:6379> keys * #查看所有的key
127.0.0.1:6379> flushall #清空所有的key
127.0.0.1:6379> flushdb #清空当前数据库的key
- redis 是单线程的。Redis是很快的,官方表示,Redis是基于内存操作,CPU不是Redis性能瓶颈,Redis的瓶颈是根据机器的内存和网络带宽,既然可以使用单线程来实现,就使用单线程了!
- Redis 为什么单线程还这么快 ?
1、误区1:高性能的服务器一定是多线程的 ?
2、误区2:多线程(CPU上下文会切换!)一定比单线程效率高!
先去CPU>内存>硬盘的速度要有所了解!
核心:redis 是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会切换:耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的,在内存情况下,这个就是最佳的方案!
RedisKey的基本命令
127.0.0.1:6379> EXISTS name #判断name这个key是否存在
127.0.0.1:6379> move name 1 #从当前数据库0移动name这个key到目标1号数据库,1代表目标数据库
127.0.0.1:6379> set name erizj
127.0.0.1:6379> EXPIRE name 10 #设置name这个key 10秒过期
127.0.0.1:6379> ttl name #查看name这个key有效时间还剩余几秒
127.0.0.1:6379> type name #查看name这个key的数据类型
Redis 五大数据类型
String
127.0.0.1:6379> set key1 v1 #设置值
OK
127.0.0.1:6379> get key1 #获得值
"v1"
127.0.0.1:6379> keys * #获得所有的key
1)"keyl"
127.0.0.1:6379> EXISTS key1 #判断某一个key是否存在
(integer)1
127.0.0.1:6379> APPEND key1 "hello" #往某一个key中追加字符串,如果当前key不存在,就相当于set key
(integer)7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> STRLEN key1 #获取字符串的长度
(integer)7
127.0.0.1:6379> APPEND keyl ",kaungshen"
(integer) 17
127.0.0.1:6379> STRLEN key1
(integer)17
127.0.0.1:6379> get key1
"vlhello ,kaungshen"
# 自增 自减 步长
127.0.0.1:6379> set views 0 #初始浏览量为0
OK
127.0.0.1:6379> get views
"0"
127.0.0.1:6379> incr views #自增1,浏览量+1
(integer)1
127.0.0.1:6379> incr views
(integer)2
127.0.0.1:6379> get views
"2"
127.0.0.1:6379> decr views #自减1,浏览量-1
(integer)1
127.0.0.1:6379> decr views
(integer)0
127.0.0.1:6379> decr views
(integer) -1
127.0.0.1:6379> get views
"-1"
127.0.0.1:6379> INCRBY views 10 #设置步长,指定增量
(integer) 9
127.0.0.1:6379> DECRBY views 5 #设置步长
(integer) 4
# 字符串范围
127.0.0.1:6379> flushdb
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> set key1 "hello,kuangshen" #设置key1的值
OK
127.0.0.1:6379> get key1
"hello,kuangshen"
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串,[0,3]
"hell"
127.0.0.1:6379> GETRANGE key1 0 -1 #获取全部的字符串,相当于get key1
"hello,kuangshen"
# 替换
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 1 xx #替换指定位置开始的字符串,逐个修改
(integer)7
127.0.0.1:6379> get key2
"axxdefg"
# setex 和 setnx
# setex (set with expire) 设置过期时间
# setnx (set if not exist) 不存在再设置【在分布式锁中会常常使用】
127.0.0.1:6379> setex key3 30 "hello" #设置key3的值并设置过期时间
OK
127.0.0.1:6379> ttl key3
(integer)26
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey
(integer)1
127.0.0.1:6379> keys *
1) "key2"
2) "mykey"
3) "keyl"
127.0.0.1:6379> ttl key3
(integer)-2
127.0.0.1:6379> setnx mykey "MongoDB" #如果当前mykey存在,则创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"
# mset 和 mget
127.0.0.1:6379> flushdb
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379> keys *
1) "k1"
2) "k2"
3) "k3"
127.0.0.1:6379> mget kl k2 k3 #同时获取多个值
1) "V1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #原子性操作,要么一起成功要么一起失败
(integer)0
127.0.0.1:6379> get k4
(nil)
# Redis 中 key 的名称支持 : 这个特殊字符
对象
set user:l {name:zhangsan,age:3} # 设置一个user:1 对象 值为 json字符来保存一个对象!#这里的key是一个巧妙的设计: user:{id}:{fi1ed},如此设计在Redis中是完全OK了!127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1)"zhangsan"
2)"2"
# getset 先get然后set
127.0.0.1:6379> getset db redis #如果不存在值则返回nil
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db mongodb #如果存在值,获取原来的值并设置新的值
"redis"
127.0.0.1:6379> get db
"mongodb"
List
- 基本的数据类型——列表
- 在Redis里,我们可以把
list
玩成栈、队列、阻塞队列!
# L 开头表示从左边开始操作,R 开头表示从右边开始操作
127.0.0.1:6379> LPUSH list one #将一个或多个值插入到列表头部(左)
(integer)1
127.0.0.1:6379> LPUSH list two
(integer)2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1 #获取list中的值
1) "three"
2) "two"
3) "one"
# Redis不区分大小写命令
127.0.0.1:6379> Rpush list righr #将一个或多个值插入到列表尾部(右)
(integer)4
127.0.0.1:6379> LRANGE list 0 1
1) "three"
2) "two"
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "righr"
127.0.0.1:6379> Lpop list #弹出list左边第一个元素
"three"
127.0.0.1:6379> Rpop list #弹出list右边第一个元素
"righr"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> LINDEX list 1 #通过下标获取list中某一个值
"one"
127.0.0.1:6379> LINDEX list 0
"two"
127.0.0.1:6379> LLEN list #返回list的长度
(integer)2
127.0.0.1:6379> RPUSH list one
(integer)3
127.0.0.1:6379> LPUSH list three
(integer)4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "one"
127.0.0.1:6379> LREM list 1 two #移除list集合中指定个数的value,精确匹配
(integer)1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "one"
3) "one"
127.0.0.1:6379> LREM list 2 one
(integer)2
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
# trim 修剪 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。
127.0.0.1:6379> flushdb
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> Rpush mylist "hello"
(integer)1
127.0.0.1:6379> Rpush mylist "hello1"
(integer)2
127.0.0.1:6379> Rpush mylist "hello2"
(integer)3
127.0.0.1:6379> Rpush mylist "hello3"
(integer)4
127.0.0.1:6379> ltrim mylist 1 2 #通过下标截取指定的长度,但是list已经被改变了,被截断了,只剩下被截取的元素
ok
127.0.0.1:6379> LRANGE mylist 0 -1
1) "hello1"
2) "hello2"
# rpoplpush 将列表右边第一个元素弹出并将其移动到指定列表到左边第一个位置
127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> Rpush mylist "hello"
(integer)1
127.0.0.1:6379> Rpush mylist "hello1"
(integer)2
127.0.0.1:6379> Rpush mylist "hello2"
(integer)3
127.0.0.1:6379> Rpoplpush mylist myotherlist
"hello2"
127.0.0.1:6379> Lrange mylist 0 -1
1) "hello"
2) "hello1"
127.0.0.1:6379> Lrange myotherlist 0 -1
1) "hello2"
# lset 将列表中指定下标的值替换为另外一个值(更新操作)
127.0.0.1:6379> flushdb
ok
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> EXISTS list
(integer) 0
127.0.0.1:6379> lset list 0 item #如果列表不存在,进行更新就会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item #如果存在,会更新当前下标的值
ok
127.0.0.1:6379> lrange list 0 0
1) "item"
# linsert 将某一个具体的值插入到列表中某个元素的前面或者后面
127.0.0.1:6379> flushdb
ok
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "world"
(integer) 2
127.0.0.1:6379> linsert mylist before "world" "other"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert mylist after world new
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"
- 实际上list是一个链表,before node after ,left right 都可以插入值
- 如果key不存在,创建新的链表
- 如果key存在,新增内容
- 如果移除了所有的值,空链表,也代表不存在
- 在两边插入或者改动值,效率最高;中间元素的改动,效率相对来说会低一点
Set
- 集合,但是set中的值是不能重复的