Redis 数据类型与使用命令大全以及Java使用

基础数据类型

具体详情可直接访问Redis官网,这里只做命令总结

  • String 二进制安全的字符串
  • Lists: 按插入顺序排序的字符串元素的集合。他们基本上就是链表(linked lists)
  • Sets: 不重复且无序的字符串元素的集合。
  • Sorted sets (ZSets),类似Sets,但是每个字符串元素都关联到一个叫score浮动数值(floating number value)。里面的元素总是通过score进行着排序,所以不同的是,它是可以检索的一系列元素。(例如你可能会问:给我前面10个或者后面10个元素)。
  • Hashes,由field和关联的value组成的map。field和value都是字符串的。这和Ruby、Python的hashes很像。
  • Bit arrays (或者说 simply bitmaps): 通过特殊的命令,你可以将 String 值当作一系列 bits 处理:可以设置和清除单独的 bits,数出所有设为 1 的 bits 的数量,找到最前的被设为 1 或 0 的 bit,等等。
  • HyperLogLogs: 这是被用于估计一个 set 中元素数量的概率性的数据结构。

redis-keys 操作

全命令:

DEL key [key ...] # 删除指定的key(一个或多个)
DUMP key # 导出key的值 序列化key
EXISTS key [key ...] # 查询一个key是否存在
EXPIRE key seconds # 设置一个key的过期的秒数
EXPIREAT key timestamp # 设置一个UNIX时间戳的过期时间
KEYS pattern # 查找所有匹配给定的模式的键
MIGRATE host port key destination-db timeout [COPY] [REPLACE] # 原子性的将key从redis的一个实例移到另一个实例
MOVE key db # 移动一个key到另一个数据库
OBJECT subcommand [arguments [arguments ...]] # 检查内部的再分配对象
PERSIST key # 移除key的过期时间
PEXPIRE key milliseconds # 设置key的有效时间以毫秒为单位
PEXPIREAT key milliseconds-timestamp # 设置key的到期UNIX时间戳以毫秒为单位
PTTL key # 获取key的有效毫秒数
RANDOMKEY # 返回一个随机的key
RENAME key newkey # 将一个key重命名
RENAMENX key newkey # 重命名一个key,新的key必须是不存在的key
RESTORE key ttl serialized-value [REPLACE] # 反序列化生成一个key,与DUMP 相对应
SORT key [BY pattern] [LIMIT offset count] [GET pattern [GET pattern ...]] [ASC|DESC] [ALPHA] [STORE destination] # 对队列、集合、有序集合排序
TTL key # 获取key的有效时间(单位:秒)
TYPE key # 获取key的存储类型
WAIT numslaves timeout # 阻塞当前客户端,直到所有以前的写命令都成功的传输和指定的slaves确认,timeout=0,将会永久阻塞直到numslaves个slaves插入后
SCAN cursor [MATCH pattern] [COUNT count] # 增量迭代key  
# SCAN 命令用于迭代当前数据库中的key集合。
# SSCAN 命令用于迭代SET集合中的元素。
# HSCAN 命令用于迭代Hash类型中的键值对。
# ZSCAN 命令用于迭代SortSet集合中的元素和元素对应的分值它们每次执行都只会返回少量元素,所以这些命令可以用于生产环境,而不会出现像 KEYS 或者 SMEMBERS 命令带来的可能会阻塞服务器的问题。
# cursor 在开始一个新的迭代时, 游标必须为 0 。增量式迭代命令在执行之后返回的, 用于延续迭代过程的游标。 
# MATCH 用于匹配 key MATCH功能对元素的模式匹配工作是在命令从数据集中取出元素后和向客户端返回元素前的这段时间内进行的, 所以如果被迭代的数据集中只有少量元素和模式相匹配, 那么迭代命令或许会在多次执行中都不返回任何元素。 
# COUNT 参数的默认值为 10 。数据集比较大时,如果没有使用MATCH 选项, 那么命令返回的元素数量通常和 COUNT 选项指定的一样, 或者比 COUNT 选项指定的数量稍多一些。在迭代一个编码为整数集合(intset,一个只由整数值构成的小集合)、 或者编码为压缩列表(ziplist,由不同值构成的一个小哈希或者一个小有序集合)时, 增量式迭代命令通常会无视 COUNT 选项指定的值, 在第一次迭代就将数据集包含的所有元素都返回给用户。

String类型

全命令:

APPEND key value # 追加一个值到key上
BITCOUNT key [start end] # 统计字符串指定起始位置的字节数
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL] # 对字符串执行任意位域整数运算
BITOP operation destkey key [key ...] # 在字符串之间执行按位运算
BITPOS key bit [start] [end] # 在字符串中查找第一个设置或清除的位
DECR key # 整数原子减1
DECRBY key decrement # 原子减指定的整数
GET key # 返回key的value
GETRANGE key start end # 获取存储在key上的值的一个子字符串
GETSET key value # 设置一个key的value,并获取设置前的值
INCR key # 执行原子加1操作
INCRBY key increment # 执行原子增加一个整数
INCRBYFLOAT key increment # 执行原子增加一个浮点数
MGET key [key ...] # 获得所有key的值
MSET key value [key value ...] # 设置多个key value
MSETNX key value [key value ...] # 设置多个key value,仅当key存在时
PSETEX key milliseconds value # 以毫秒为单位设置键的值和到期时间
SET key value [EX seconds] [PX milliseconds] [NX|XX] # 设置一个key的value值
SETEX key seconds value # 设置key-value并设置过期时间(单位:秒)
SETNX key value # 设置的一个关键的价值,只有当该键不存在
SETRANGE key offset value # 替换指定返回子串
STRLEN key # 获取指定key值的长度

字符串实操运用:

127.0.0.1:6379> set hello world  # 设置 值 key = hello value = world
OK
127.0.0.1:6379> get hello # 获取 hello的值
"world"
127.0.0.1:6379> set fristKey "hello word"
OK
127.0.0.1:6379> get fristKey
"hello word"
127.0.0.1:6379> keys *  # 查询所有键
1) "fristKey"
2) "hello"
127.0.0.1:6379> setex hello 10 redis # 设置 hello 的有效时间为 10s 并设置值为redis
OK
127.0.0.1:6379> ttl hello #查询剩余时间
(integer) 4
127.0.0.1:6379> get hello  # hello已失效
(nil)                       
127.0.0.1:6379> get fristKey
"hello word"
127.0.0.1:6379> set fristKey "hello redis" # 修改fristKey的值
OK
127.0.0.1:6379> setnx fristKey "is exists" # 如果不存在fristKey ,则设置或修改值
(integer) 0
127.0.0.1:6379> get fristKey
"hello redis"
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3   # 批量设置key  (原子操作,一起成功或一起失败)
OK
127.0.0.1:6379> mget k1 k2 k3 fristKey # 批量获取 
1) "v1"
2) "v2"
3) "v3"
4) "hello redis"
127.0.0.1:6379> msetnx k5 c2 k1 c1  k6 c3 # k1 失败后 后续设置也一同失败
(integer) 0
127.0.0.1:6379> keys *
1) "fristKey"
2) "k2"
3) "k3"
4) "k1"
127.0.0.1:6379> mget k5 k1 k2 k3
1) (nil)
2) "v1"
3) "v2"
4) "v3"

########################################################################################

127.0.0.1:6379> incr num  # 设置num 自增1,
(integer) 1
127.0.0.1:6379> decr num # 设置num 自减1,
(integer) 0
127.0.0.1:6379> incrby num 2 # 设置num += 2 ,
(integer) 2
127.0.0.1:6379> incrby num 10  # 设置num += 10 ,
(integer) 12
127.0.0.1:6379> decrby num 5  # 设置num -= 5 ,
(integer) 7

########################################################################################
127.0.0.1:6379> strlen fristKey # 获取字符串长度
(integer) 11
127.0.0.1:6379> get fristKey
"hello redis"
127.0.0.1:6379> getrange fristKey 1 4 # 截取字符串 索引[1,4]
"ello"
127.0.0.1:6379> getrange fristKey 1 -1 # 截取字符串 索引[1,len-1]
"ello redis"
127.0.0.1:6379> getrange fristKey 0 -1 # 截取字符串 索引[0,len-1]  等价于 get
"hello redis"
127.0.0.1:6379> setrange fristKey 2 "la"  # 替换  从索引 2 开始替换 子串
(integer) 11
127.0.0.1:6379> getrange fristKey 0 -1  
"helao redis"
127.0.0.1:6379> append fristKey " this " # 追加 在字符串后面追加子串
(integer) 17
127.0.0.1:6379> getrange fristKey 0 -1
"helao redis this "
127.0.0.1:6379> getset fristKey "hello worl"  # 获取原来值设置新值
"helao redis this "
127.0.0.1:6379> getrange fristKey 0 -1
"hello worl"

字符串的使用总结

  1. 普通的 get 、 set操作,基本的键值对操作,有效时间的设置 (setex),仅新增操作(setnx),批量操作 mget mset
  2. 可进行数统计,自增 (incr ,incrby)、自减 (decr,decrby)
  3. 字符串操作 : 获取长度 (strlen)、截取范围 (getrange)、替换 (setrange)、追加子串 (append)

Lists 类型

基本前缀 为 L 的都是list的操作命令,list 底层 是链表结构

全命令:

BLPOP key [key ...] timeout # 删除,并获得该列表中的第一元素,或阻塞,直到有一个可用
BRPOP key [key ...] timeout # 删除,并获得该列表中的最后一个元素,或阻塞,直到有一个可用
BRPOPLPUSH source destination timeout # 弹出一个列表的值,将它推到另一个列表,并返回它;或阻塞,直到有一个可用
LINDEX key index # 获取一个元素,通过其索引列表
LINSERT key BEFORE|AFTER pivot value # 在列表中的另一个元素之前或之后插入一个元素
LLEN key # 获得队列(List)的长度
LPOP key # 从队列的左边出队一个元素
LPUSH key value [value ...] # 从队列的左边入队一个或多个元素
LPUSHX key value # 当队列存在时,从队到左边入队一个元素
LRANGE key start stop # 从列表中获取指定返回的元素
LREM key count value # 从列表中删除元素
LSET key index value # 设置队列里面一个元素的值
LTRIM key start stop # 修剪到指定范围内的清单
RPOP key # 从队列的右边出队一个元
RPOPLPUSH source destination # 删除列表中的最后一个元素,将其追加到另一个列表
RPUSH key value [value ...] # 从队列的右边入队一个元素
RPUSHX key value # 从队列的右边入队一个元素,仅队列存在时有效

实操运用:

127.0.0.1:6379> lpush list 0 1 2 3  # 从左边往key=list 中插入数据
(integer) 4
127.0.0.1:6379> rpush list 4 5 6  # 从右边 往 list 中插入数据
(integer) 7
127.0.0.1:6379> lrange list 0 -1  # 获取 list [0,len-1] 的数据
1) "3"
2) "2"
3) "1"
4) "0"
5) "4"
6) "5"
7) "6"
127.0.0.1:6379> llen list # 获取 list 的长度
(integer) 7
127.0.0.1:6379> lpop list 2 # 从左边取出 两条数据
1) "3"
2) "2"
127.0.0.1:6379> rpop list  # 从右边取出 一条数据
1) "6"
127.0.0.1:6379> lrange list 0 -1 
1) "1"
2) "0"
3) "4"
4) "5"
127.0.0.1:6379> lindex list 2 # 获取索引为2的元素
"4"
127.0.0.1:6379> linsert list before 0 2 # 在 元素 "0" 之前插入 "2" ,after 为之后插入
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "1"
2) "2"
3) "0"
4) "4"
5) "5"
127.0.0.1:6379> lrem list 2 0 # 删除2条 元素"0",这里因为list中只有一条0 所以只删除了1条
(integer) 1

#########################################################################################

127.0.0.1:6379> lrange list 0 -1 
1) "1"
2) "2"
3) "4"
4) "5"
127.0.0.1:6379> ltrim list 1 2 # 截断 list,只保留 [1,2]
OK
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "4"
127.0.0.1:6379> rpush list 3 5 6 7 8 9
(integer) 8
127.0.0.1:6379> lrange list 0 -1
1) "2"
2) "4"
3) "3"
4) "5"
5) "6"
6) "7"
7) "8"
8) "9"

######################################################################################
127.0.0.1:6379> brpoplpush newlist list 10  # 阻塞操作,从newlist右边取出一条元素插入到list,当newlist为空,最大等待10s
(nil)
(10.07s)
127.0.0.1:6379> rpoplpush list newlist # 从list 右边取出一条元素插入到newlist
"9"
127.0.0.1:6379> lrange newlist 0 -1
1) "9"
127.0.0.1:6379> brpoplpush newlist list 10  # 阻塞操作,从newlist右边取出一条元素插入到list,当newlist不为空,直接操作
"9"
127.0.0.1:6379> lrange list 0 -1
1) "9"
2) "2"
3) "4"
4) "3"
5) "5"
6) "6"
7) "7"
8) "8"

list 使用总结

  1. 双向链表的使用: push(lpush 左 rpush 右 插入值, 集合存在才操作 lpushx,rpushx)、pop (l 左 r 右 取出值) 、获取长度(llen)、获取索引处元素 (lindex)、删除对应元素(lrem)、在对应元素插入值(linsert),

  2. 范围获取 : range ( lrange 获取指定返回元素) 、截断(ltrim)

  3. 队列操作 : rpoplpush (从源集合右边取出 往目标集合 左边插入 , 源集合 == 目标集合 集合就成了循环列表)

    阻塞操作 (b开头,brpoplpush、blpop、brpop 当源集合为空时,操作会阻塞等待,最大为设定的等待时间,非空直接操作)

Sets 类型

无序不重复的集合

全命令(s开头):

SADD key member [member ...] # 添加一个或者多个元素到集合(set)里
SCARD key # 获取集合里面的元素数量
SDIFF key [key ...] # 获得队列不存在的元素
SDIFFSTORE destination key [key ...] # 获得队列不存在的元素,并存储在一个关键的结果集
SINTER key [key ...] # 获得两个集合的交集
SINTERSTORE destination key [key ...] # 获得两个集合的交集,并存储在一个关键的结果集
SISMEMBER key member # 确定一个给定的值是一个集合的成员
SMEMBERS key # 获取集合里面的所有元素
SMOVE source destination member # 移动集合里面的一个元素到另一个集合
SPOP key [count] # (随机)删除并获取(1或count)个集合里面的元素
SRANDMEMBER key [count] # 从集合里面随机获取(1或count)个元素
SREM key member [member ...] # 从集合里删除一个或多个元素
SUNION key [key ...] # 获取多个set并集
SUNIONSTORE destination key [key ...] # 合并set元素,并将结果存入新的set里面
SSCAN key cursor [MATCH pattern] [COUNT count] # 迭代set里面的元素

实操运用:

127.0.0.1:6379> sadd set1 1 2 3 4 5 6 6 7  # 增加set元素,6重复不会添加
(integer) 7
127.0.0.1:6379> smembers set1 # 获取所有set元素
1) "1"
2) "2"
3) "3"
4) "4"
5) "5"
6) "6"
7) "7"
127.0.0.1:6379> scard set1 # 获取set中元素个数
(integer) 7
127.0.0.1:6379> SRANDMEMBER set1 2
1) "5"
2) "6"
127.0.0.1:6379> SRANDMEMBER set1 # 随机获取一个元素
"5"
127.0.0.1:6379> SRANDMEMBER set1 
"6"
127.0.0.1:6379> SRANDMEMBER set1 
"7"
127.0.0.1:6379> SRANDMEMBER set1 
"2"
127.0.0.1:6379> SRANDMEMBER set1 
"6"
127.0.0.1:6379> SRANDMEMBER set1 
"1"
127.0.0.1:6379> SRANDMEMBER set1 
"2"
127.0.0.1:6379> SRANDMEMBER set1 
"7"
127.0.0.1:6379> SRANDMEMBER set1 
"5"
127.0.0.1:6379> SPOP set1 # 随机删除并获取一个元素
"7"
127.0.0.1:6379> SPOP set1
"1"
127.0.0.1:6379> SPOP set1
"6"
127.0.0.1:6379> smembers set1
1) "2"
2) "3"
3) "4"
4) "5"
127.0.0.1:6379> srem set1 0 1 2 3 # 删除存在的元素
(integer) 2
127.0.0.1:6379> smembers set1
1) "4"
2) "5"
127.0.0.1:6379> sismember set1 4  # 查看4是否在set1中 等价于 java中 Set#contains
(integer) 1
127.0.0.1:6379> sismember set1 0
(integer) 0

##########################################################################################
127.0.0.1:6379> sadd set2 0 1 2 3 4 
(integer) 5
127.0.0.1:6379> sdiff set1 set2  # 求 set1 与 set2 的差集 (set1 - set2)
1) "5"
127.0.0.1:6379> sdiff set2 set1
1) "0"
2) "1"
3) "2"
127.0.0.1:6379> sadd set3 5 6 7 8
(integer) 4
127.0.0.1:6379> sdiff set1 set2 set3 # 求 set1 与 set2、set3 的差集 (set1 - set2 - set3)
(empty array)
127.0.0.1:6379> sunion set1 set2 set3 # 求 set1 与 set2、set3 的并集 (set1 ∪ set2 ∪ set3)
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
127.0.0.1:6379> sunionstore setall set1 set2 set3 # 将 set1 与 set2、set3 的并集 (set1 ∪ set2 ∪ set3),放入setall中
(integer) 9
127.0.0.1:6379> smembers setall
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"
127.0.0.1:6379> sinter set1 set2 setall   # 求 set1 与 set2、setall 的交集 (set1 ∩ set2 ∩ set3)
1) "4"

127.0.0.1:6379> smove set2 setall 0 # 从set2 移动元素0到setall
(integer) 1
127.0.0.1:6379> smembers set2
1) "1"
2) "2"
3) "3"
4) "4"
127.0.0.1:6379> smembers setall
1) "0"
2) "1"
3) "2"
4) "3"
5) "4"
6) "5"
7) "6"
8) "7"
9) "8"


使用总结:

  1. 保证数据无重复
  2. 随机值的处理 SRANDMEMBER 、SPOP
  3. 集合交、并、差集的处理 SINTER、 SUNION 、SDIFF

Hashes 类型

哈希类型,每个key 下都是 k-v的结构,使用与String类型(仅多嵌套一层k-v)相似,更适合存对象

全命令(h开头)

HMSET key field value [field value ...] # 设置hash字段值
HSET key field value # 设置hash里面一个字段的值 (也可以设置多个字段,等价于hmset)
HGET key field # 获取hash中field的值
HGETALL key # 从hash中读取全部的域和值
HMGET key field [field ...] # 获取hash里面指定字段的值
HLEN key # 获取hash里所有字段的数量
HSTRLEN key field # 获取hash里面指定field的长度
HEXISTS key field # 判断field是否存在于hash中
HSETNX key field value # 设置hash的一个字段,只有当这个字段不存在时有效
HKEYS key # 获取hash的所有字段
HVALS key # 获得hash的所有值
HDEL key field [field ...] # 删除一个或多个Hash的field
HINCRBY key field increment # 将hash中指定域的值增加给定的数字
HINCRBYFLOAT key field increment # 将hash中指定域的值增加给定的浮点数
HSCAN key cursor [MATCH pattern] [COUNT count] # 迭代hash里面的元素

实操运用:

127.0.0.1:6379> hset user:1 name zhangsan age 18 sex 1  # 设置user:1对象的属性值 name=zhangsan age=18 sex=1
(integer) 3
127.0.0.1:6379> hget user:1 name # 获取user:1 .name属性值
"zhangsan"
127.0.0.1:6379> hgetall user:1 # 获取user:1 全部属性字段与值
1) "name"
2) "zhangsan"
3) "age"
4) "18"
5) "sex"
6) "1"
127.0.0.1:6379> hlen user:1  # 获取user:1 键值对个数
(integer) 3
127.0.0.1:6379> hstrlen user:1 name # 获取user:1.name 的长度
(integer) 8
127.0.0.1:6379> HEXISTS user:1 weight  # 查看user:1 是否存在 weight字段
(integer) 0
127.0.0.1:6379> hset user:1 weight 120 # 设置user:1.weight=120
(integer) 1
127.0.0.1:6379> hsetnx user:1 weight 100 # user:1.weight 不存在 设置user:1.weight=100
(integer) 0
127.0.0.1:6379> hmget user:1 name sex weight
1) "zhangsan"
2) "1"
3) "120"
127.0.0.1:6379> hkeys user:1 # 获取user:1 所有属性字段
1) "name"
2) "age"
3) "sex"
4) "weight"
127.0.0.1:6379> hvals user:1 # 获取user:1 所有属性值
1) "zhangsan"
2) "18"
3) "1"
4) "120"
127.0.0.1:6379> hincrby user:1 age 1 # 将age字段+1
(integer) 19
127.0.0.1:6379> hincrby user:1 age -10 # 将age字段-1
(integer) 9
127.0.0.1:6379> hincrbyfloat user:1 age 0.5 # 将age字段+0.5
"9.5"
127.0.0.1:6379> hincrbyfloat user:1 age -2.556  # 将age字段-2.556
"6.944"
127.0.0.1:6379> hincrby user:1 age 1  # 只能使用整数,小数会报错
(error) ERR hash value is not an integer

使用总结:

  1. 主要用于存储对象,可直接对字段值进行操作,操作与String基本相同

ZSet 类型

有序的set,与set项目,多了一个score分数的维度,便于排序

全命令(z开头都是zset):

ZADD key [NX|XX] [CH] [INCR] score member [score member ...] #添加到有序set的一个或多个成员,或更新的分数,如果它已经存在
# XX: 仅仅更新存在的成员,不添加新成员。
# NX: 不更新存在的成员。只添加新成员。
# CH: 修改返回值为发生变化的成员总数,原始是返回新添加成员的总数 (CH 是 changed 的意思)。更改的元素是新添加的成员,已经存在的成员更新分数。 所以在命令中指定的成员有相同的分数将不被计算在内。注:在通常情况下,ZADD返回值只计算新添加成员的数量。
# INCR: 当ZADD指定这个选项时,成员的操作就等同ZINCRBY命令,对成员的分数进行递增操作。
ZCARD key #获取一个排序的集合中的成员数量
ZCOUNT key min max #返回分数范围内的成员数量
ZINCRBY key increment member #增量的一名成员在排序设置的评分
ZINTERSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] # 相交多个排序集和排序的设置存储在一个新的zset中
ZLEXCOUNT key min max # 返回成员之间的成员数量
ZPOPMAX key [count] # 删除 score 最小的元素
ZPOPMIN key [count] # 删除 score 最大的元素
ZRANGE key start stop [WITHSCORES] # 根据指定的index返回,返回sorted set的成员列表  WITHSCORES为是否携带score
ZRANGEBYLEX key min max [LIMIT offset count] # 返回指定成员区间内的成员,按score正序排列, 分数必须相同。
ZREVRANGEBYLEX key max min [LIMIT offset count] # 返回指定成员区间内的成员,按score倒序排列, 分数必须相同
ZRANGEBYSCORE key min max [WITHSCORES] [LIMIT offset count] # 返回有序集合中指定分数区间内的成员,分数由低到高排序。
ZRANK key member # 确定在排序集合成员的索引
ZREM key member [member ...] # 从排序的集合中删除一个或多个成员
ZREMRANGEBYLEX key min max # 删除名称按字典由低到高排序成员之间所有成员。
ZREMRANGEBYRANK key start stop # 在排序设置的所有成员在给定的索引中删除
ZREMRANGEBYSCORE key min max # 删除一个排序的设置在给定的分数所有成员
ZREVRANGE key start stop [WITHSCORES] # 在排序的设置返回的成员范围,通过索引,下令从分数高到低
ZREVRANGEBYSCORE key max min [WITHSCORES] [LIMIT offset count] # 返回有序集合中指定分数区间内的成员,分数由高到低排序。
ZREVRANK key member # 确定指数在排序集的成员,下令从分数高到低
ZSCORE key member # 获取成员在排序设置相关的比分
ZUNIONSTORE destination numkeys key [key ...] [WEIGHTS weight [weight ...]] [AGGREGATE SUM|MIN|MAX] # 合并多个排序集和排序的设置存储在一个新的zset中
ZSCAN key cursor [MATCH pattern] [COUNT count] # 迭代sorted sets里面的元素

实操运用

127.0.0.1:6379> zadd zset1 1 a1 2 a2 3 a3 4 a4 # 设置zset 值
(integer) 4
127.0.0.1:6379> zadd zset1 incr 1 a1 # 设置 a1 的score 自增1
"2" 
127.0.0.1:6379> zadd zset1 incr 3 a1 # 设置 a1 的score 自增3
"5"
127.0.0.1:6379> zrange zset1 0 -1  withscores # 根据索引获取zset1中的元素 ,withscores 显示score值
1) "a2"
2) "2"
3) "a3"
4) "3"
5) "a4"
6) "4"
7) "a1"
8) "5"
127.0.0.1:6379> zrangebyscore zset1 -inf inf withscores # 根据score范围 获取zset1中的元素 ,withscores 显示score值,-inf inf 负无穷到正无穷
1) "a2"
2) "2"
3) "a3"
4) "3"
5) "a4"
6) "4"
7) "a1"
8) "5"
127.0.0.1:6379> zrangebyscore zset1 4 5 withscores
1) "a4"
2) "4"
3) "a1"
4) "5"
127.0.0.1:6379> zcard zset1  # 获取zset1元素个数
(integer) 4
127.0.0.1:6379> zcount zset1 0 4 # 统计score 范围内数量
(integer) 3
127.0.0.1:6379> zincrby zset1 -3 a1 # 设置a1 score 自增-3
"2"
127.0.0.1:6379> zcount zset1 0 4 
(integer) 4
127.0.0.1:6379> zrangebylex zset1 - +  # 根据区间获取元素, - 最小值 + 最大值  [ 包含 ( 不包含
1) "a0"
2) "a2"
3) "a3"
127.0.0.1:6379> zrangebylex zset1 (a0 [a3  # 根据区间获取元素 在范围内 (a0,a3]的元素 
1) "a2"
2) "a3"
127.0.0.1:6379> zrank zset1 a0  # 获取元素索引
(integer) 0
127.0.0.1:6379> zrank zset1 a2
(integer) 1

使用总结:

  1. 适用于元素自动去重、排序
  2. 交、并集 需要存储且没有差集

特殊数据类型

Geo 类型 (地理位置)

用于存在地理城市的经纬度,并提供了经纬度计算的操作

全命令:

GEOADD key longitude latitude member [longitude latitude member ...] # 添加一个或多个地理空间位置到sorted set(是一个排序set)
GEOHASH key member [member ...] # 返回一个标准的地理空间的Geohash字符串
GEOPOS key member [member ...] # 返回地理空间的经纬度
GEODIST key member1 member2 [unit] # 返回两个地理空间之间的距离
GEORADIUS key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] # 查询指定半径内所有的地理空间元素的集合。
GEORADIUSBYMEMBER key member radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] # 查询指定半径内匹配到的最大距离的一个地理空间元素。

实操使用:

redis-master:0>geoadd loc 103.30 30.2837 c1 # 增加 key 一个 c1 地理元素,longitude 经度 latitude 维度
"1"
redis-master:0>geoadd loc 103.98 31.38137 c2
"1"
redis-master:0>geohash loc c1 c2  # 将 c1、c2 转换为hash值
 1)  "wm3kq8uz260"
 2)  "wm9fw0gctx0"
redis-master:0>geopos loc c1 c2 # 获取c1、c2 的 经度、维度
 1)    1)   "103.299998939037323"
  2)   "30.28369891573603212"

 2)    1)   "103.97999793291091919"
  2)   "31.38137005267240198"

redis-master:0>geodist loc c1 c2 m # c1 c2 相距 直线距离 m 米
"138287.5103"
redis-master:0>geodist loc c1 c2 km # c1 c2 相距 直线距离 km 千米
"138.2875"
redis-master:0>georadius loc 104.01928 30.7328 200 km withdist # 查询 坐标(104.01928,30.7328) 200公里以内的元素,并返回直线距离
 1)    1)   "c1"
  2)   "85.1238"

 2)    1)   "c2"
  2)   "72.2351"


redis-master:0>GEORADIUSBYMEMBER loc c2 200 km WITHDIST # 寻找c2 200km以内节点
 1)    1)   "c1"
  2)   "138.2875"

 2)    1)   "c2"
  2)   "0.0000"

使用总结

  1. 可存储地理位置,比较两点直线距离,可运用 附近的人、位置打卡

HyperLogLogs 类型(基数统计)

如同sets 一样,元素不会重复,但只会进行计数。使用恒定量的内存!在最坏的情况下为 12kb,

全命令:(pf开头)

PFADD key element [element ...]  # 将指定元素添加到HyperLogLog
PFCOUNT key [key ...] # 统计所有key 元素(去重)个数
PFMERGE destkey sourcekey [sourcekey ...] # 合并所有sourceKey中到destkey中

实操运用

127.0.0.1:6379> PFADD blog:1 1 3 4 6 5 7 8  # blog1添加统计元素
(integer) 1
127.0.0.1:6379> pfadd blog:1 3 23 5 45 6 45 
(integer) 1
127.0.0.1:6379> pfcount blog:1  # 统计blog1 元素
(integer) 9
127.0.0.1:6379> pfadd blog:2 1 2 3 4 5 6 7 8 9 # blog2添加统计元素
(integer) 1
127.0.0.1:6379> pfmerge blog:count blog:1 blog:2 # 将blog1、blog2的元素合并到blogcount
OK
127.0.0.1:6379> PFCOUNT blog:count
(integer) 11

使用总结

  1. 用户访问量等 统计只增数量(按值去重)的应用

Bitmap(位存储 )

将一个key的值当做一个字符串,对位进行操作

全命令:(BIT相关)

GETBIT key offset # 返回位的值存储在关键的字符串值的偏移量(索引)。
SETBIT key offset value # 设置偏移量(索引)的值 value 为 0或1
BITCOUNT key [start end] # 统计字符串指定起始位置的字节数
BITFIELD key [GET type offset] [SET type offset value] [INCRBY type offset increment] [OVERFLOW WRAP|SAT|FAIL] # 对字符串执行任意位域整数运算
# GET <type> <offset> – 返回指定的位域
# SET <type> <offset> <value> – 设置指定位域的值并返回它的原值
# INCRBY <type> <offset> <increment> – 自增或自减(如果increment为负数)指定位域的值并返回它的新值
# OVERFLOW [WRAP|SAT|FAIL] 通过设置溢出行为来改变调用INCRBY指令的后序操作
# WRAP: 回环算法,适用于有符号和无符号整型两种类型。对于无符号整型,回环计数将对整型最大值进行取模操作(C语言的标准行为)。对于有符号整型,上溢从最负的负数开始取数,下溢则从最大的正数开始取数,例如,如果i8整型的值设为127,自加1后的值变为-128。
# SAT: 饱和算法,下溢之后设为最小的整型值,上溢之后设为最大的整数值。例如,i8整型的值从120开始加10后,结果是127,继续增加,结果还是保持为127。下溢也是同理,但量结果值将会保持在最负的负数值。
# FAIL: 失败算法,这种模式下,在检测到上溢或下溢时,不做任何操作。相应的返回值会设为NULL,并返回给调用者。
# type: 当需要一个整型时,有符号整型需在位数前加i,无符号在位数前加u。例如,u8是一个8位的无符号整型,i16是一个16位的有符号整型。有符号整型最大支持64位,而无符号整型最大支持63位。对无符号整型的限制,是由于当前Redis协议不能在响应消息中返回64位无符号整数。
BITOP operation destkey key [key ...] # 在字符串之间执行按位运算
BITPOS key bit [start] [end] # 在字符串中查找第一个设置或清除的位

使用总结

模式:使用 bitmap 实现用户上线次数统计

Bitmap 对于一些特定类型的计算非常有效。

假设现在我们希望记录自己网站上的用户的上线频率,比如说,计算用户 A 上线了多少天,用户 B 上线了多少天,诸如此类,以此作为数据,从而决定让哪些用户参加 beta 测试等活动 —— 这个模式可以使用 SETBITBITCOUNT 来实现。

比如说,每当用户在某一天上线的时候,我们就使用 SETBIT ,以用户名作为 key ,将那天所代表的网站的上线日作为 offset 参数,并将这个 offset 上的为设置为 1 。

举个例子,如果今天是网站上线的第 100 天,而用户 peter 在今天阅览过网站,那么执行命令 SETBIT peter 100 1 ;如果明天 peter 也继续阅览网站,那么执行命令 SETBIT peter 101 1 ,以此类推。

当要计算 peter 总共以来的上线次数时,就使用 BITCOUNT 命令:执行 BITCOUNT peter ,得出的结果就是 peter 上线的总天数。

性能

前面的上线次数统计例子,即使运行 10 年,占用的空间也只是每个用户 10*365 比特位(bit),也即是每个用户 456 字节。对于这种大小的数据来说, BITCOUNT 的处理速度就像 GETINCR 这种 O(1) 复杂度的操作一样快。

如果你的 bitmap 数据非常大,那么可以考虑使用以下两种方法:

  • 将一个大的 bitmap 分散到不同的 key 中,作为小的 bitmap 来处理。使用 Lua 脚本可以很方便地完成这一工作。
  • 使用 BITCOUNT 的 start 和 end 参数,每次只对所需的部分位进行计算,将位的累积工作(accumulating)放到客户端进行,并且对结果进行缓存 (caching)。

事务

命令

multi # 开始事务
exec # 执行事务
discard # 放弃事务
WATCH key [key ...] # 锁定key直到执行了 MULTI/EXEC 命令,乐观锁
UNWATCH #取消锁命令

中文相关

默认redis 会将中文进行转义,在客户端中get多数会乱码,如果客户端测试的话可以在链接时加上

redis-cli --raw

在java中操作一般要使用序列化模式,才不会乱码

Jedis

jedis 是 Java版的redis链接客服端,使用非常简单,基本与上述命令一致

引入依赖

<dependencies>
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.1.0</version>
    </dependency>
</dependencies>

代码测试

public class JedisTest {

    public static void main(String[] args) {
        // 开启客户端链接
        Jedis jedis = new Jedis(host,port);
        // 若有密码需要输入密码
        jedis.auth(password);

        // 基础链接测试
        System.out.println(jedis.ping());
        jedis.flushDB();
        System.out.println(jedis.set("k1", "v1"));
        System.out.println(jedis.get("k1"));

        // 设置乐观锁
        jedis.watch("k1");
        Transaction multi = jedis.multi();
        try {
            // 事务开始后,使用事务对象调用命令
            multi.mset("k1","d2","k2","v2","k3","v3");
            //制造异常查看事务
//            int i = 1/0;
            multi.lpush("list","a","b","c","d");

            // 执行事务
            multi.exec();
        }catch (Exception e){
            e.printStackTrace();
            // 放弃事务
            multi.discard();
            jedis.unwatch();
        }finally {
            System.out.println(jedis.mget("k1","k2","k3"));
            System.out.println(jedis.lrange("list",0,-1));
        }
        // 关闭链接
        jedis.close();

    }
}

Jedis的优缺点:

优点:

  1. 使用直连: 简单方便,适用于少量长期连接的场景

  2. 使用连接池: 无需每次连接生成Jedis对象,降低开销

  3. 使用连接池的形式保护和控制资源的使用

缺点:

  1. 使用直连:存在每次新建/关闭TCP连接开销
  2. 使用直连:资源无法控制,极端情况下出现连接泄漏
  3. 使用连接池:Jedis对象线程不安全(Lettuce对象是线程安全的)
  4. 使用连接池:相对于直连,使用更加麻烦,尤其在资源的管理上需要很多参数来保证,一旦规划不合理也会出现问题

Springboot

引入redis 的starter

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

springboot中使用redis客户端,是spring-data提供的,主要封装了jedis 与 Lettuce

外部采用redisTemplate进行操作 (每次操作都需要传入的是可序列化的对象)

redisTemplate. keys或通用的操作命令

redisTemplate.opsForValue() String(bitmap也同为归入String)
redisTemplate.opsForList() List
redisTemplate.opsForHash() hash
redisTemplate.opsForSet() set
redisTemplate.opsForZSet() zset
redisTemplate.opsForGeo() geo
redisTemplate.opsForHyperLogLog() HyperLogLog

配置

application.yml:

spring:
  redis:
    # 密码默认为空
    password: 123456  
    # ip地址默认为localhost
    host: localhost
    # 端口号默认为6379
    port: 6379
    # 连接超时时间(毫秒)
    connect-timeout: 1000
    jedis:
      pool:
        # 连接池最大连接数(使用负值表示没有限制)
        max-active: 200
        # 连接池最大阻塞等待时间(使用负值表示没有限制)
        max-wait: 1000ms
        # 连接池中的最大空闲连接
        max-idle: 10
        # 连接池中的最小空闲连接
        min-idle: 0

配置RedisTemplate,

RedisConf.java:

@Component
public class RedisConf {

    /**
     * 配置  redisTemplate key-value序列化
     * @param factory
     * @return
     */
    @Bean
    @SuppressWarnings("all")
    public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);
        Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
        ObjectMapper om = new ObjectMapper();
        om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        om.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
        jackson2JsonRedisSerializer.setObjectMapper(om);
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        // key采用String的序列化方式
        template.setKeySerializer(stringRedisSerializer);
        // hash的key也采用String的序列化方式
        template.setHashKeySerializer(stringRedisSerializer);
        // value序列化方式采用jackson
        template.setValueSerializer(jackson2JsonRedisSerializer);
        // hash的value序列化方式采用jackson
        template.setHashValueSerializer(jackson2JsonRedisSerializer);
        template.afterPropertiesSet();
        return template;
    }
}

封装通用的简单操作

(e.printStackTrace() 看项目需求替换为 log.error())

RedisUtil.java:

@Component
public final class RedisUtil {
    
    @Resource(name = "redisTemplate")
    private RedisTemplate<String, Object> redisTemplate;

    // =============================common============================
    /**
     * 指定缓存失效时间
     *
     * @param key  键
     * @param time 时间(秒)
     * @return
     */
    public boolean expire(String key, long time) {
        try {
            if (time > 0) {
                redisTemplate.expire(key, time, TimeUnit.SECONDS);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据key 获取过期时间
     *
     * @param key 键 不能为null
     * @return 时间(秒) 返回0代表为永久有效
     */
    public long getExpire(String key) {
        return redisTemplate.getExpire(key, TimeUnit.SECONDS);
    }

    /**
     * 判断key是否存在
     *
     * @param key 键
     * @return true 存在 false不存在
     */
    public boolean hasKey(String key) {
        try {
            return redisTemplate.hasKey(key);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除缓存
     *
     * @param key 可以传一个值 或多个
     */
    public void del(String... key) {
        if (key != null && key.length > 0) {
            if (key.length == 1) {
                redisTemplate.delete(key[0]);
            } else {
                redisTemplate.delete((Collection<String>) CollectionUtils.arrayToList(key));
            }
        }
    }

    // ============================String=============================

    /**
     * 普通缓存获取
     *
     * @param key 键
     * @return 值
     */
    public Object get(String key) {
        return key == null ? null : redisTemplate.opsForValue().get(key);
    }

    /**
     * 普通缓存放入
     *
     * @param key   键
     * @param value 值
     * @return true成功 false失败
     */
    public boolean set(String key, Object value) {
        try {
            redisTemplate.opsForValue().set(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }

    }

    /**
     * 普通缓存放入并设置时间
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒) time要大于0 如果time小于等于0 将设置无限期
     * @return true成功 false 失败
     */
    public boolean set(String key, Object value, long time) {
        try {
            if (time > 0) {
                redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);
            } else {
                set(key, value);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 递增
     *
     * @param key   键
     * @param delta 要增加几(大于0)
     * @return
     */
    public long incr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递增因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, delta);
    }

    /**
     * 递减
     *
     * @param key   键
     * @param delta 要减少几(小于0)
     * @return
     */
    public long decr(String key, long delta) {
        if (delta < 0) {
            throw new RuntimeException("递减因子必须大于0");
        }
        return redisTemplate.opsForValue().increment(key, -delta);
    }

    // ================================Map=================================

    /**
     * HashGet
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return 值
     */
    public Object hget(String key, String item) {
        return redisTemplate.opsForHash().get(key, item);
    }

    /**
     * 获取hashKey对应的所有键值
     *
     * @param key 键
     * @return 对应的多个键值
     */
    public Map<Object, Object> hmget(String key) {
        return redisTemplate.opsForHash().entries(key);
    }

    /**
     * HashSet
     *
     * @param key 键
     * @param map 对应多个键值
     * @return true 成功 false 失败
     */
    public boolean hmset(String key, Map<String, Object> map) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * HashSet 并设置时间
     *
     * @param key  键
     * @param map  对应多个键值
     * @param time 时间(秒)
     * @return true成功 false失败
     */
    public boolean hmset(String key, Map<String, Object> map, long time) {
        try {
            redisTemplate.opsForHash().putAll(key, map);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 向一张hash表中放入数据,如果不存在将创建
     *
     * @param key   键
     * @param item  项
     * @param value 值
     * @param time  时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间
     * @return true 成功 false失败
     */
    public boolean hset(String key, String item, Object value, long time) {
        try {
            redisTemplate.opsForHash().put(key, item, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 删除hash表中的值
     *
     * @param key  键 不能为null
     * @param item 项 可以使多个 不能为null
     */
    public void hdel(String key, Object... item) {
        redisTemplate.opsForHash().delete(key, item);
    }

    /**
     * 判断hash表中是否有该项的值
     *
     * @param key  键 不能为null
     * @param item 项 不能为null
     * @return true 存在 false不存在
     */
    public boolean hHasKey(String key, String item) {
        return redisTemplate.opsForHash().hasKey(key, item);
    }

    /**
     * hash递增 如果不存在,就会创建一个 并把新增后的值返回
     *
     * @param key  键
     * @param item 项
     * @param by   要增加几(大于0)
     * @return
     */
    public double hincr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, by);
    }

    /**
     * hash递减
     *
     * @param key  键
     * @param item 项
     * @param by   要减少记(小于0)
     * @return
     */
    public double hdecr(String key, String item, double by) {
        return redisTemplate.opsForHash().increment(key, item, -by);
    }

    // ============================set=============================

    /**
     * 根据key获取Set中的所有值
     *
     * @param key 键
     * @return
     */
    public Set<Object> sGet(String key) {
        try {
            return redisTemplate.opsForSet().members(key);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 根据value从一个set中查询,是否存在
     *
     * @param key   键
     * @param value 值
     * @return true 存在 false不存在
     */
    public boolean sHasKey(String key, Object value) {
        try {
            return redisTemplate.opsForSet().isMember(key, value);
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将数据放入set缓存
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSet(String key, Object... values) {
        try {
            return redisTemplate.opsForSet().add(key, values);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 将set数据放入缓存
     *
     * @param key    键
     * @param time   时间(秒)
     * @param values 值 可以是多个
     * @return 成功个数
     */
    public long sSetAndTime(String key, long time, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().add(key, values);
            if (time > 0) {
                expire(key, time);
            }
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 获取set缓存的长度
     *
     * @param key 键
     * @return
     */
    public long sGetSetSize(String key) {
        try {
            return redisTemplate.opsForSet().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 移除值为value的
     *
     * @param key    键
     * @param values 值 可以是多个
     * @return 移除的个数
     */
    public long setRemove(String key, Object... values) {
        try {
            Long count = redisTemplate.opsForSet().remove(key, values);
            return count;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
    // ===============================list=================================

    /**
     * 获取list缓存的内容
     *
     * @param key   键
     * @param start 开始
     * @param end   结束 0 到 -1代表所有值
     * @return
     */
    public List<Object> lGet(String key, long start, long end) {
        try {
            return redisTemplate.opsForList().range(key, start, end);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 获取list缓存的长度
     *
     * @param key 键
     * @return
     */
    public long lGetListSize(String key) {
        try {
            return redisTemplate.opsForList().size(key);
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }

    /**
     * 通过索引 获取list中的值
     *
     * @param key   键
     * @param index 索引 index>=0时, 0 表头,1 第二个元素,依次类推;index<0时,-1,表尾,-2倒数第二个元素,依次类推
     * @return
     */
    public Object lGetIndex(String key, long index) {
        try {
            return redisTemplate.opsForList().index(key, index);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, Object value) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, Object value, long time) {
        try {
            redisTemplate.opsForList().rightPush(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @return
     */
    public boolean lSet(String key, List<Object> value) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 将list放入缓存
     *
     * @param key   键
     * @param value 值
     * @param time  时间(秒)
     * @return
     */
    public boolean lSet(String key, List<Object> value, long time) {
        try {
            redisTemplate.opsForList().rightPushAll(key, value);
            if (time > 0) {
                expire(key, time);
            }
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 根据索引修改list中的某条数据
     *
     * @param key   键
     * @param index 索引
     * @param value 值
     * @return
     */
    public boolean lUpdateIndex(String key, long index, Object value) {
        try {
            redisTemplate.opsForList().set(key, index, value);
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    /**
     * 移除N个值为value
     *
     * @param key   键
     * @param count 移除多少个
     * @param value 值
     * @return 移除的个数
     */
    public long lRemove(String key, long count, Object value) {
        try {
            Long remove = redisTemplate.opsForList().remove(key, count, value);
            return remove;
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
    }
}

测试

@SpringBootTest
class NosqlBootApplicationTests {

    @Test
    void contextLoads() {
    }

    @Autowired
    RedisTemplate<String,Object> redisTemplate;
    @Autowired
    RedisUtil redisUtil;

    @Test
    void restTest(){
        // 普通操作
        redisUtil.set("k1","s1");
        long num1 = redisUtil.incr("num1", 2);
        System.out.println(num1);

        // 事务操作
        List<Object> execute = redisTemplate.execute(new SessionCallback<List<Object>>() {
            @Override
            public List<Object> execute(RedisOperations redisOperations) throws DataAccessException {
                redisOperations.watch(Arrays.asList("k1","k2"));
                redisOperations.multi();
                redisOperations.opsForValue().multiSet(Map.of("k1", "v1", "k2", "v2")); // Map.of是JAVA9 出现的,8以下的自行put
                redisOperations.opsForValue().multiGet(Arrays.asList("k1", "k2"));
                return redisOperations.exec();
            }
        });
        System.out.println(execute);
    }
}
2
[true, [v1, v2]]
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值