redis.md
redis学习
Nosql
数据访问量越来越大:
- 单机
- Memcached
数据类型
127.0.0.1:6379> ping PONG 127.0.0.1:6379> keys * # 查看所有键 (empty array) 127.0.0.1:6379> set age "敖德萨大" # 设置值 OK 127.0.0.1:6379> keys * 1) "age" 127.0.0.1:6379> keys age 1) "age" 127.0.0.1:6379> get age # 获取值 "\xe6\x95\x96\xe5\xbe\xb7\xe8\x90\xa8\xe5\xa4\xa7" 127.0.0.1:6379> EXISTS age # 判断key是否存在 (integer) 1 127.0.0.1:6379> EXISTS agea (integer) 0 127.0.0.1:6379> move age # 语法错误,需要数据库 (error) ERR wrong number of arguments for 'move' command 127.0.0.1:6379> move age 1 # 移除库1中的age (integer) 1 # 过期时间设置 127.0.0.1:6379> set name "IOIOIO" OK 127.0.0.1:6379> keys name 1) "name" 127.0.0.1:6379> get name "IOIOIO" 127.0.0.1:6379> EXPIRE name 10 # 设置过期时间 (integer) 1 127.0.0.1:6379> ttl name # 查看存活时间 (integer) 6 127.0.0.1:6379> ttl name (integer) 3 127.0.0.1:6379> ttl name (integer) -2 127.0.0.1:6379> ttl name (integer) -2 127.0.0.1:6379> keys * (empty array) 127.0.0.1:6379> get name (nil) # 查看类型 127.0.0.1:6379> set age 12 OK 127.0.0.1:6379> type age string
String
场景:
- string
- 计数器
- 对象缓存存储
- cookie
127.0.0.1:6379> set name "abcdefghijklmn" OK 127.0.0.1:6379> append name " 123456" # 追加,如果key不存在则创建空并追加 (integer) 21 # 返回append之后的长度 127.0.0.1:6379> get name "abcdefghijklmn 123456" 127.0.0.1:6379> STRLEN name # 获取长度 (integer) 21 # 加减 127.0.0.1:6379> set views 0 OK 127.0.0.1:6379> type views string 127.0.0.1:6379> type view # key不存在时类型为none none 127.0.0.1:6379> incr views # 加 1 (integer) 1 127.0.0.1:6379> type views string 127.0.0.1:6379> get views "1" 127.0.0.1:6379> DECR views # 减 1 (integer) 0 127.0.0.1:6379> get views "0" 127.0.0.1:6379> INCRBY views 98 # 步长98自增 (integer) 98 127.0.0.1:6379> DECRBY views 9 (integer) 89 127.0.0.1:6379> APPEND views io9 # views == "9io9" (integer) 5 127.0.0.1:6379> incr views # 自增错误,非整数 (error) ERR value is not an integer or out of range # 获取字符串范围 127.0.0.1:6379> set name "hello, world!" OK 127.0.0.1:6379> GETRANGE name 0 -1 # -1 代表最后一位 "hello, world!" 127.0.0.1:6379> GETRANGE name 0 100 # 超过本身长度不报错 "hello, world!" 127.0.0.1:6379> GETRANGE name 0 3 # 一般获取 "hell" 127.0.0.1:6379> GETRANGE name 100 -1 # 返回空 "" 127.0.0.1:6379> GETRANGE name 100 9 "" 127.0.0.1:6379> GETRANGE name 100 900 "" 127.0.0.1:6379> GETRANGE name -1 0 "" 127.0.0.1:6379> GETRANGE names 0 -1 # key不存在时返回“” "" # 指定范围替换 127.0.0.1:6379> SETRANGE name 1 xx (integer) 13 127.0.0.1:6379> get name "hxxlo, world!" # setex (set with expire) 设置值的同时过期时间 # setnx (set if not exist) 不存在时才设置 127.0.0.1:6379> setex key3 30 "Wait ...." OK 127.0.0.1:6379> get key3 "Wait ...." 127.0.0.1:6379> ttl key3 (integer) 18 127.0.0.1:6379> setnx mykey "first" # 不存在,设置成功 (integer) 1 127.0.0.1:6379> setnx mykey "second" # 已存在,设置失败 (integer) 0 127.0.0.1:6379> get mykey "first" 127.0.0.1:6379> get key3 # 不存在,返回nil (nil) # 批量设置 127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 批量设置 OK 127.0.0.1:6379> mget k1 v1 k2 k3 #批量获取 1) "v1" 2) (nil) 3) "v2" 4) "v3" 127.0.0.1:6379> msetnx k1 OP k9 v9 # 保证一致性,k1已存在,设置失败,k9不再进行设置 (integer) 0 127.0.0.1:6379> keys * 1) "k1" 2) "k3" 3) "k2" 4) "mykey" 127.0.0.1:6379> get k9 (nil) # 对象保存 127.0.0.1:6379> mset user:1:name zhangsan user:1:age 18 OK 127.0.0.1:6379> mget user:1:name user:1:age 1) "zhangsan" 2) "18" # getset,获取当前的值并设置新值 127.0.0.1:6379> getset db redis (nil) 127.0.0.1:6379> get db "redis" 127.0.0.1:6379> getset db mysql "redis"
List
列表:存储是链表(双向?)
|--------------------------------------| | |---| |---| |---| | | L | 1 | | 2 | | 3 | .... R | | |---| |---| |---| | |--------------------------------------|
- 在两边操作,效率比在中间元素操作高
- 消息队列(lpush, rpop) 栈(lpush,)
# l --> list | left 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 # 获取指定范围,输出栈的形式 1) "three" 2) "two" 3) "one" 127.0.0.1:6379> LRANGE list 0 1 1) "three" 2) "two" # r --> right 127.0.0.1:6379> rpush list right # 向右边(尾部)插入 (integer) 4 127.0.0.1:6379> LRANGE list 0 -1 1) "three" 2) "two" 3) "one" 4) "right" # lpop rpop 127.0.0.1:6379> lpop list # 弹出最左边的元素 "three" 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "one" 3) "right" 127.0.0.1:6379> rpop list # 弹出最右边的元素 "right" 127.0.0.1:6379> LRANGE list 0 -1 1) "two" 2) "one" 127.0.0.1:6379> lindex list 1 # 通过下标获取 "one" 127.0.0.1:6379> lindex list 0 "two" 127.0.0.1:6379> Llen list # 返回列表长度 (integer) 2 # 移除值 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "three" 3) "three" 4) "two" 5) "one" 127.0.0.1:6379> lrem list 1 one # 移除 1 个 one 元素 (integer) 1 127.0.0.1:6379> lrem list 2 three # 移除 2 个 three 元素 (integer) 2 127.0.0.1:6379> lrem list 2 threeS (integer) 0 127.0.0.1:6379> lrange list 0 -1 1) "three" 2) "two" # ltrim 截取 127.0.0.1:6379> LRANGE list 0 -1 (empty array) 127.0.0.1:6379> rpush list hello0 (integer) 1 127.0.0.1:6379> rpush list hello1 (integer) 2 127.0.0.1:6379> rpush list hello2 (integer) 3 127.0.0.1:6379> rpush list hello3 (integer) 4 127.0.0.1:6379> ltrim list 2 3 # ltrim key start end (会改变list!) OK 127.0.0.1:6379> LRANGE list 0 -1 1) "hello2" 2) "hello3" # rpoplpush 右弹出并左压进其他列表 (弹出最后一个元素并放入其他列表的第一个元素) 127.0.0.1:6379> LRANGE list 0 -1 1) "hello2" 2) "hello3" 127.0.0.1:6379> rpoplpush list newlist # source desition "hello3" 127.0.0.1:6379> LRANGE list 0 -1 1) "hello2" 127.0.0.1:6379> LRANGE newlist 0 -1 1) "hello3" # 更新值 lset, 插入值 linsert 127.0.0.1:6379> LRANGE list 0 -1 1) "v0" 2) "v1" 3) "v2" 4) "v3" 5) "v3" 127.0.0.1:6379> lset list 3 VALUE OK 127.0.0.1:6379> LRANGE list 0 -1 1) "v0" 2) "v1" 3) "v2" 4) "VALUE" 5) "v3" 127.0.0.1:6379> lset list 5 VALUE # 超出范围 (error) ERR index out of range 127.0.0.1:6379> linsert list before v1 INSERT_V1 # 在值v之前插入 (integer) 6 127.0.0.1:6379> linsert list after v2 INSERT_V2 # 在值v2之后插入 (integer) 7 127.0.0.1:6379> LRANGE list 0 -1 1) "v0" 2) "INSERT_V1" 3) "v1" 4) "v2" 5) "INSERT_V2" 6) "VALUE" 7) "v3"
Set
# sadd 添加 smembers 列出所有成员 127.0.0.1:6379> sadd set hello (integer) 1 127.0.0.1:6379> sadd set hello1 (integer) 1 127.0.0.1:6379> sadd set hello2 (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "hello2" 2) "hello" 3) "hello1" # sismember 判断是否存在某一元素 127.0.0.1:6379> SISMEMBER set hello # 存在 (integer) 1 127.0.0.1:6379> SISMEMBER set hello12 # 不存在 (integer) 0 # scard 获取集合元素的个数 127.0.0.1:6379> scard set (integer) 3 # srem 移除元素 127.0.0.1:6379> srem set (error) ERR wrong number of arguments for 'srem' command 127.0.0.1:6379> srem set hello (integer) 1 127.0.0.1:6379> SMEMBERS set 1) "hello2" 2) "hello1" # srandmember set [count] 随机抽取指定个数的元素 # spop set 随机删除元素 # smove source destition value 移动指定元素 # sdiff 差集 # sinter 交集 # sunion 并集
Hash
# hset hget hgetall 127.0.0.1:6379> hset hash k1 v1 k2 v2 k3 v3 (integer) 3 127.0.0.1:6379> hget hash k1 "v1" 127.0.0.1:6379> hgetall hash 1) "k1" 2) "v1" 3) "k2" 4) "v2" 5) "k3" 6) "v3" # hdel 删除 127.0.0.1:6379> hdel hash k1 (integer) 1 # hlen 长度 127.0.0.1:6379> hgetall hash 1) "k2" 2) "v2" 3) "k3" 4) "v3" 127.0.0.1:6379> HLEN hash (integer) 2 # hexists 是否存在 127.0.0.1:6379> HEXISTS hash k1 # 不存在 (integer) 0 127.0.0.1:6379> HEXISTS hash k2 # 存在 (integer) 1 # hkeys 只获取key, hvals 只获取value 127.0.0.1:6379> hkeys hash 1) "k2" 2) "k3" 127.0.0.1:6379> HVALS hash 1) "v2" 2) "v3" # hincrby hsetnx
Zset
有序集合
# zadd zrange 127.0.0.1:6379> zadd myset 1 one (integer) 1 127.0.0.1:6379> zadd myset 2 two (integer) 1 127.0.0.1:6379> zadd myset 3 three (integer) 1 127.0.0.1:6379> ZRANGE myset 0 -1 1) "one" 2) "two" 3) "three" # zrangebyscore 排序 127.0.0.1:6379> zrangebyscore myset -inf +inf 1) "one" 2) "two" 3) "three" # 同时输出score 127.0.0.1:6379> zrangebyscore myset -inf 10 withscores 1) "one" 2) "1" 3) "two" 4) "2" 5) "three" 6) "3" # zrem 移除 127.0.0.1:6379> zrangebyscore myset -inf 10 withscores 1) "one" 2) "1" 3) "two" 4) "2" 5) "three" 6) "3" # zcard 查看数量 # zcount 获取指定区间的元素数量 127.0.0.1:6379> zcount myset 0 9 (integer) 2
Geospatial
地理位置
底层是zset
# geoadd 添加 127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing (integer) 1 127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai (integer) 1 127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing (integer) 1 # geopos 获取 127.0.0.1:6379> geopos china:city beijing 1) 1) "116.39999896287918091" 2) "39.90000009167092543" # geodist 计算直线距离 127.0.0.1:6379> geodist china:city beijing shanghai m "1067378.7564" 127.0.0.1:6379> geodist china:city beijing shanghai km "1067.3788" # georadious 计算给定坐标给定半径内的key 127.0.0.1:6379> georadius china:city 110 30 1000 km 1) "chongqing" # 同时限制数量,给出坐标和距离 127.0.0.1:6379> georadius china:city 110 30 2000 km withdist withcoord count 1 1) 1) "chongqing" 2) "341.9374" 3) 1) "106.49999767541885376" 2) "29.52999957900659211" # groradiousmember 找出给定城市给定距离的城市 127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1300 km 1) "shanghai" 2) "beijing" # geohash 返回地址的hash,失去精度但仍指向同一区域 127.0.0.1:6379> geohash china:city beijing 1) "wx4fbxxfke0" # zrem 移除 zrange 查看 127.0.0.1:6379> ZREM china:city beijing (integer) 1 127.0.0.1:6379> ZRANGE china:city 0 -1 1) "chongqing" 2) "shanghai"
Hyperloglog
基数
:两个集合不重复的元素,可以有误差(0.81%的误差)
优点:
- 占用内存固定,264不同的元素,需要12KB
网页的访问数:传统方式使用set保存用户ID来避免同一用户访问造成的多次计数。
# pfadd 添加 127.0.0.1:6379> pfadd key 1 2 3 4 5 6 7 8 9 0 (integer) 1 127.0.0.1:6379> pfadd key1 ! 2 3 $ 5 6 & 8 9 ) (integer) 1 # pfcount 计算基数 127.0.0.1:6379> pfcount key key1 (integer) 14 127.0.0.1:6379> pfcount key (integer) 10 127.0.0.1:6379> pfcount key1 (integer) 10 # pmerge 合并key和key1到key3 127.0.0.1:6379> PFMERGE key3 key key1 OK 127.0.0.1:6379> pfcount key3 (integer) 14
BitMap
位存储
统计用户活跃|不活跃、登录|未登录、打卡|未打卡……只有两个状态的,可以使用Bitmaps!
Bitmaps位图,数据结构,操作二进制位进行记录
# setbit 设置位 127.0.0.1:6379> setbit sign 5 1 # 第5天的状态 (integer) 0 127.0.0.1:6379> setbit sign 6 0 # 第6天的状态 (integer) 0 127.0.0.1:6379> setbit sign 7 1 # 第7天的状态 (integer) 0 # getbit 获取 127.0.0.1:6379> setbit sign 1 0 (integer) 1 127.0.0.1:6379> getbit sign 1 (integer) 0 # bitcount 计数 127.0.0.1:6379> bitcount sign (integer) 7 127.0.0.1:6379> bitcount sign 0 -1 (integer) 7
事务
Redis单条命令保证原子性,但事务不保证原子性!
redis的事务:
- 开启事务(multi)
- 命令入队()
- 执行事务(exec)
Redis可以实现乐观锁。
# multi exec 127.0.0.1:6379> multi # 开启事务 OK 127.0.0.1:6379(TX)> set k1 v1 QUEUED 127.0.0.1:6379(TX)> set k2 v2 QUEUED 127.0.0.1:6379(TX)> get v3 QUEUED 127.0.0.1:6379(TX)> set v3 V3 QUEUED 127.0.0.1:6379(TX)> exec # 执行 1) OK 2) OK 3) (nil) 4) OK # discard 放弃事务 127.0.0.1:6379> multi OK 127.0.0.1:6379(TX)> set key6 v6 QUEUED 127.0.0.1:6379(TX)> discard OK 127.0.0.1:6379> exec (error) ERR EXEC without MULTI
错误处理
- 代码异常:所有事务不执行
- 运行异常: 其他命令正常执行,错误直接忽略
乐观锁
- 悲观锁:认为什么时候都有问题,无论做什么都会加锁
- 乐观锁: 认为什么都没问题, 不会上锁!更新数据时去判断,在此期间是否有人修改过此数据。
- 获取version
- 更新时比较version
# 正常执行成功 127.0.0.1:6379> set money 100 OK 127.0.0.1:6379> set out 0 OK 127.0.0.1:6379> watch money # 监视money对象 OK 127.0.0.1:6379> mutil (error) ERR unknown command `mutil`, with args beginning with: 127.0.0.1:6379> multi # 事务正常结束,期间数据未被改动,执行成功! OK 127.0.0.1:6379(TX)> decrby money 20 QUEUED 127.0.0.1:6379(TX)> INCRBY out 20 QUEUED 127.0.0.1:6379(TX)> exec 1) (integer) 80 2) (integer) 20
# 多线程执行失败 # 连接1 127.0.0.1:6379> set money 100 OK 127.0.0.1:6379> watch money # 进行监视(加锁) OK 127.0.0.1:6379> MULTI OK 127.0.0.1:6379(TX)> INCRBY money 20 QUEUED 127.0.0.1:6379(TX)> exec # 先去执行连接B (nil) # 事务执行失败 127.0.0.1:6379> unwatch # 取消监视 OK 127.0.0.1:6379> watch money # 监视新值 OK # ………………………继续上面的操作(自弦索) # 连接B 127.0.0.1:6379> get money "100" 127.0.0.1:6379> DECRBY money 90 (integer) 10
Jedis
Java操作Redis
Jedis方法与redis命令一致
public static void main(String[] args) { // 连接Jedis Jedis jedis = new Jedis(); // Jedis 即所有指令 System.out.println(jedis.ping("fdsfds")); } }
SpringBoot整合
Spring-Data
本文作者:nsfoxer
本文链接:https://www.cnblogs.com/nsfoxer/p/16321399.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?