Redis快速入门

一、基本命令

1、切换数据库(select)

redis默认有16个数据库,默认使用的是第0个数据库
在这里插入图片描述

切换数据的命令:select 数字

localhost:6379> select 2
OK							# 切换成功
localhost:6379[2]>          # 6379[2] 表示第三个数据库

  
  
2、set 和 get 方法

命令1:set [key] [value]

localhost:6379[2]> set name tiger
OK
localhost:6379[2]>

  
  

命令2:get [key]

localhost:6379[2]> get name
"tiger"
localhost:6379[2]>

  
  
3、查看数据库的大小(DESIZE)

命令:dbsize

localhost:6379[2]> dbsize
(integer) 1
localhost:6379[2]>

  
  
4、查看所有key

命令:keys *

localhost:6379[2]> keys *
1) "name"
2) "old"
localhost:6379[2]>

  
  
5、清空数据库

清空所有数据库:flushall

清空当前数据库:flushdb

localhost:6379[2]> flushdb
OK
localhost:6379[2]> keys *
(empty array)				# 已经清空
localhost:6379[2]>

  
  

二、redis 的数据类型

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询。 Redis 内置了 复制(replication),LUA脚本(Lua scripting), LRU驱动事件(LRU eviction),事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel)和自动 分区(Cluster)提供高可用性(high availability)。


1、Redis_key

① 查看某一个key是否存在

127.0.0.1:6379> keys *
1) "myhash"
2) "mylist"
3) "counter:__rand_int__"
4) "name"
5) "key:__rand_int__"
127.0.0.1:6379> exists name			# 查看 name 是否存在
(integer) 1							# 1 表示存在

  
  

② 移除当前库中指定的的key到另一个数据库中

127.0.0.1:6379> move name 1		# 将当前数据库中的 name 移动到 数据库1中
(integer) 0						# 0 表示移动失败 , 1表示成功

  
  

③ 设置/查看指定key的过期时间

127.0.0.1:6379> expire name 10			# 设置 name 的存活时间为 10 秒
(integer) 1
127.0.0.1:6379> ttl name				# 查看 name 的存活时间
(integer) 4								# 4 表示 name 的存活时间剩余 4秒
127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> ttl name
(integer) 0								# name 已过期
127.0.0.1:6379> get name				# name 已经查看不到了
(nil)

  
  

④ 查看可以的类型

127.0.0.1:6379> type myhash				# 查看 myhash 的数据类型
hash									# myhash 的数据类型为 hash

2、String 字符串类型的讲解

① 字符串追加(不存在key,则会新建):append key value

127.0.0.1:6379> set name studioustiger
OK
127.0.0.1:6379> get name
"studioustiger"
127.0.0.1:6379> append name -is-a-man   # 在name的后面追加 -is-a-man
(integer) 22
127.0.0.1:6379> get name	
"studioustiger-is-a-man"				# 追加成功

② 获取key的长度:strlen key

127.0.0.1:6379> get name
"studioustiger-is-a-man"
127.0.0.1:6379> strlen name   	#获取 name 的长度
(integer) 22

③ 自增(加一):incr key

127.0.0.1:6379> set age 15		# 设置 age 初始值为 15
OK
127.0.0.1:6379> incr age		# age 自增 1
(integer) 16
127.0.0.1:6379> incr age		# age 自增 1
(integer) 17
127.0.0.1:6379> get age
"17"							# 当前 age 的值为 17 ,说明自增成功

 
 

④ 自减(减一):decr key

127.0.0.1:6379> get age
"17"
127.0.0.1:6379> decr age		# age 自减
(integer) 16
127.0.0.1:6379> get age
"16"							# 自减成功

 
 

⑤ 指定步长自增:incrby key 步长

127.0.0.1:6379> get age				# 当前 age 为 16
"16"
127.0.0.1:6379> incrby age 10		# 自增 10
(integer) 26
127.0.0.1:6379> get age
"26"								# 现在是 256

 
 

⑥ 指定步长自减:decrby key 步长

127.0.0.1:6379> get age				# 当前 age 为26
"26"
127.0.0.1:6379> decrby age 5		# 自减 5
(integer) 21
127.0.0.1:6379> get age
"21"								# 现在是 21

 
 

⑦ 获取字符串指定范围:getrange key start end

127.0.0.1:6379> get name
"studioustiger-is-a-man"
127.0.0.1:6379> getrange name 0 7  # 获取从name的索引为0到索引为7的片段(刚好8个字符)
"studious"

 
 

⑧ 替换字符串:setrange key index newstr 将index位置对应的字符替换成newstr

127.0.0.1:6379> get name				# 获取name值
"studioustiger-is-a-man"			
127.0.0.1:6379> setrange name 0 S		# 将name的索引为0的字符替换成S
(integer) 22
127.0.0.1:6379> setrange name 8 T		# 将name的索引为8的字符替换成T
(integer) 22
127.0.0.1:6379> get name				# 获取name值
"StudiousTiger-is-a-man"

⑨ 创建key的同时设置存活时间:setex key seconds value (set with expire)

127.0.0.1:6379> setex gender 30 man  # 创建key为gender,值为man,存活时间为30秒
OK
127.0.0.1:6379> ttl gender			 # 查看gender的存活时间
(integer) 25
127.0.0.1:6379> ttl gender			 # 查看gender的存活时间
(integer) 21

 
 

⑩ 只有当key不存在的时候才会创建成功:setnx key value (set if not exist)

127.0.0.1:6379> setnx name tiger     # 创建 键为name,值为tiger(存在)
(integer) 0							 # 0 表示执行失败
127.0.0.1:6379> get name			 
"StudiousTiger-is-a-man"			 # 发现name已经被提前创建了
127.0.0.1:6379> setnx hobby sleep	 # 创建 键为hobby,值为sleep(不存在)
(integer) 1							 # 创建成功
127.0.0.1:6379> get hobby
"sleep"								 # hobby确实创建成功

 
 

11 批量创建:mset key1 value1 key2 value2 ...

127.0.0.1:6379> mset name2 tiger age2 10 hobby eat #同时创建 name2、age2、hobby
OK
127.0.0.1:6379> mget name2 age2 hobby			   # 同时获取
1) "tiger"
2) "10"
3) "eat"

 
 

12 批量创建(原子性):msetnx key1 key2

127.0.0.1:6379> msetnx name3 tiger age3 10 hobby play
(integer) 0		# 创建失败,因为hobby之前已经存在
127.0.0.1:6379> msetnx name3 tiger age3 10 hobby3 play
(integer) 1		# 创建成功,因为hobby3之前不存在

 
 

13 批量获取:mget key1 key2

127.0.0.1:6379> mget name3 age3 hobby3
1) "tiger"
2) "10"
3) "play"

 
 

14 设置/获取对象:mset user:1:name tiger user:1:age 18

127.0.0.1:6379> mset user:1:name studioustiger user:1:age 18 user:1:gender 18
OK						# 设置成功
127.0.0.1:6379> mget user:1:name user:1:age user:1:gender
1) "studioustiger"		# 获取成功
2) "18"
3) "18"

 
 

15 先get旧值,再set新值:getset key value

127.0.0.1:6379> getset user:1:gender man #现获取user:1:gender的值,再将其设置为man
"18"
127.0.0.1:6379> get user:1:gender		 # 我们发现当前user:1:gender的值已经变成man
"man"

String 的应用场景:value除了是字符串还可以是数字

  • 文章阅读计数器
  • 统计多单位的数量
  • 统计粉丝数
  • 对象缓存存储

3、List 列表类型的讲解

list实际上是一个链表,所以链表可以进行的操作在Redis中也是可以实现的


左侧存值:Lpush key value01 value02 ...
从左侧查看指定范围的值:Lrange key start end (查看所有的值:Lrange key 0 -1)

因为是从左边存值,又是从左边取值,所以效果和栈(先进后出)类似。但是这里的Lrange不是pop而是print。

127.0.0.1:6379> lpush mylist tiger01 tiger02 # 从list的左依次插入tiger01 tiger02
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1			 # 从list的左侧依次将mylist中的值打印出来
1) "tiger02"
2) "tiger01"

 
 


右侧存值:Lpush key value
从左侧查看指定范围的值:Lrange key start end (查看所有的值:Lrange key 0 -1)

因为是从左边存值,又是从左边取值,所以效果和队列(先进先出)类似。但是这里的Lrange不是pop而是print。

127.0.0.1:6379> rpush mylist tiger01 tiger02 # 从list的左依次插入tiger01 tiger02
(integer) 2
127.0.0.1:6379> lrange mylist 0 -1			 # 从list的左侧依次将mylist中的值打
1) "tiger01"
2) "tiger02"

 
 


弹出最左侧的值:Lpop key
弹出最右侧的值:Rpop key

127.0.0.1:6379> rpush list data01 data02 data03 data04
(integer) 4
127.0.0.1:6379> lrange list 0 -1      # 当前最左侧的值是data01,最右侧的值是data04
1) "data01"
2) "data02"
3) "data03"
4) "data04"
127.0.0.1:6379> lpop list			  # 弹出最左侧的值
"data01"
127.0.0.1:6379> lrange list 0 -1	  # 很明显,data01已经被弹出了
1) "data02"
2) "data03"
3) "data04"
127.0.0.1:6379> rpop list			  # 弹出最右侧的值
"data04"
127.0.0.1:6379> lrange list 0 -1	  # 很明显,data04已经被弹出了
1) "data02"
2) "data03"
127.0.0.1:6379>

 
 

移除指定的值:Lrem key count value

127.0.0.1:6379> rpush list data01 data02 data02 data03 data04
(integer) 5
127.0.0.1:6379> lrange list 0 -1		# 可以发现,list中是可以存储相同的value的
1) "data01"
2) "data02"
3) "data02"
4) "data03"
5) "data04"
127.0.0.1:6379> lrem list 1 data04      # 删除list中一个data04
(integer) 1
127.0.0.1:6379> lrange list 0 -1		# 删除成功
1) "data01"
2) "data02"
3) "data02"
4) "data03"
127.0.0.1:6379> lrem list 2 data02		# 删除;list中两个data02
(integer) 2
127.0.0.1:6379> lrange list 0 -1		# 很明显,删除成功
1) "data01"
2) "data03"

 
 


通过下标获取list中的值:Lindex key index
获取list的长度:Llen key

127.0.0.1:6379> rpush list I Love U
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "I"
2) "Love"
3) "U"
127.0.0.1:6379> Lindex list 1    # 获取list中索引为1的值
"Love"
127.0.0.1:6379> llen list		 # 获取list的长度
(integer) 3

 
 

截断list中指定的位置:Ltrim key start end

127.0.0.1:6379> lrange list 0 -1
1) "I"
2) "Love"
3) "U"
127.0.0.1:6379> Ltrim list 1 2         # 保留list中索引1到2的内容
OK
127.0.0.1:6379> lrange list 0 -1       # 很明显,截断成功
1) "Love"
2) "U"

将已存在的list中的最右侧的值剪切到其他list中:RpopLpush existList otherList

127.0.0.1:6379> lrange mywords 0 -1          # 目前 mywords 中有 4 个 value
1) "I"
2) "Love"
3) "U"
4) "Baby"
127.0.0.1:6379> rpoplpush mywords demo       # 将 mywords 中最右侧的 value 弹出,并写入 demo 中
"Boby"
127.0.0.1:6379> lrange mywords 0 -1          # mywords 中确实没有 Baby 了
1) "I"
2) "Love"
3) "U"
127.0.0.1:6379> lrange demo 0 -1			 # demo 中确实被写入了 Baby
1) "Baby"

更新list中的指定位置的值:Lset key index value

127.0.0.1:6379> lrange mywords 0 -1    # 现在mywords中索引为2的value的值是U
1) "I"
2) "Love"
3) "U"
127.0.0.1:6379> lset mywords 2 You     # 替换mywords中索引为2的值为You
OK
127.0.0.1:6379> lrange mywords 0 -1    # 很明显,替换成功
1) "I"
2) "Love"
3) "You"

 
 

向list中指定值得前面或后面插入值:Linsert key before/after existValue value

127.0.0.1:6379> lrange mywords 0 -1
1) "I"
2) "Love"
3) "You"
127.0.0.1:6379> Linsert mywords after You Too  # 在 You 的后面插入 Too
(integer) 4
127.0.0.1:6379> lrange mywords 0 -1			   # 很明显,插入成功
1) "I"
2) "Love"
3) "You"
4) "Too"

 
 

4、Set 集合类型的讲解

set是一个无序不重复集合。


向set集合中添加元素:Sadd key value01 value02 ...
打印set集合中的元素:Smembers key

127.0.0.1:6379> sadd set hello world tiger # 向集合中添加元素
(integer) 3
127.0.0.1:6379> smembers set               # 打印set中的元素
1) "hello"
2) "tiger"
3) "world"

 
 

判断set集合中是否存在某一个元素:Sismember key value

127.0.0.1:6379> smembers set
1) "hello"
2) "tiger"
3) "world"
127.0.0.1:6379> sismember set tiger       # 判断tiger是否在set中
(integer) 1						# 1表示存在
127.0.0.1:6379> sismember set studious	  # 判断studious是否存在set中
(integer) 0						# 0表示不存在

 
 

获取set 集合中的size :Scard key

127.0.0.1:6379> Smembers set    # 可以发现set中有三个元素
1) "hello"
2) "tiger"
3) "world"
127.0.0.1:6379> Scard set      # 打印 set 中元素的个数
(integer) 3

移除set中的元素:Srem key value01 value02 ...

127.0.0.1:6379> smembers set			# 此时set中有6个元素
1) "tiger"
2) "I"
3) "world"
4) "u"
5) "hello"
6) "Love"
127.0.0.1:6379> srem set I Love u      # 移除"I" "Love" "u"这三个元素
(integer) 3
127.0.0.1:6379> Smembers set		   # 很明显,移除成功
1) "hello"
2) "world"
3) "tiger"

 
 

随机取出set中的指定个元素:Srangemember key count

127.0.0.1:6379> Smembers set
1) "is"
2) "name"
3) "My"
4) "StudiousTiger"
127.0.0.1:6379> srandmember set 2   # 随机从set中取出2个元素
1) "name"
2) "is"
127.0.0.1:6379> srandmember set 2   # 随机从set中取出两个元素
1) "My"
2) "is"
127.0.0.1:6379> Smembers set        # 可以发现元素的个数没有变化,所以只是取出不是移除
1) "is"
2) "name"
3) "My"
4) "StudiousTiger"

 
 

随机移除set中的元素:Spop key count

127.0.0.1:6379> SMEMBERS set
1) "is"
2) "name"
3) "My"
4) "StudiousTiger"
127.0.0.1:6379> Spop set 1       # 从set中随机移除一个元素
1) "My"
127.0.0.1:6379> Spop set 1		 # 从set中随机移除一个元素
1) "name"
127.0.0.1:6379> SMEMBERS set     # 很明显元素确实被移除了
1) "is"
2) "StudiousTiger"

 
 

将一个指定的值移动到另一个集合中:Smove currentSet targetSet value

127.0.0.1:6379> SMEMBERS set1
1) "u"
2) "love"
3) "too"
4) "i"
127.0.0.1:6379> Smove set1 set2 too   # 将set1中的"too"剪切到set2
(integer) 1
127.0.0.1:6379> SMEMBERS set1         # set1中的"too"消失了
1) "u"
2) "love"
3) "i"
127.0.0.1:6379> SMEMBERS set2         # set2中多了一个"too"
1) "too"

 
 

set的集合:差集、交集、并集
可以用到微博,B站,共同关注(交集)的问题的解决上
key1、key2的差集:Sdeff key1 key2
key1、key2的交集:Sinter key1 key2
key1、key2的并集:Sunion key1 key2

127.0.0.1:6379> SADD set1 a b c d		# set1集合中存入 a b c d
(integer) 4
127.0.0.1:6379> SADD set2 c d e f		# set2集合中存入 c d e f
127.0.0.1:6379>
127.0.0.1:6379> Sdiff set1 set2			# 获取set1和set2的差集(不同)
1) "b"
2) "a"
127.0.0.1:6379> Sinter set1 set2		# 获取set1和set2的交集(相同)
1) "d"
2) "c"
127.0.0.1:6379> Sunion set1 set2		#获取set1和set2的并集(合并)
1) "e"
2) "a"
3) "f"
4) "d"
5) "b"
6) "c"

 
 

5、Hash 哈希类型的讲解

我们可以认为Hash类型是HashMap即可。


向hash中存值(k-v):Hset key field value
从hash中取值(k-v):Hget key field

127.0.0.1:6379> Hset user name tiger   # 存值,key为user,field为name,value为tiger
(integer) 1
127.0.0.1:6379> Hget user name         # 取值
"tiger"

 
 


向hash中存多个值(k-v):Hmset key field01 value01 field02 value02 ...
从hash中取多个值(k-v):Hmget key field01 field02 ...

127.0.0.1:6379> Hmset user name tiger age 18 gender man  #存多值
OK
127.0.0.1:6379> Hmget user name age gender				 # 取多值
1) "tiger"
2) "18"
3) "man"

 
 

获取hash中所有的值(k-v):Hgetall key

127.0.0.1:6379> Hgetall user	# 获取所有的field和value
1) "name"						# field
2) "tiger"						# value
3) "age"						# field
4) "18"							# value
5) "gender"						# field
6) "man"						# value

 
 

删除hash中的值:Hdel key field01 field02 ...

127.0.0.1:6379> Hgetall user
1) "name"
2) "tiger"
3) "age"
4) "18"
5) "gender"
6) "man"
127.0.0.1:6379> Hdel user age gender	# 删除user中的age和gender
(integer) 2
127.0.0.1:6379> Hgetall user			# 确实已经删除成功
1) "name"
2) "tiger"

 
 

获取hash的长度:Hlen key

127.0.0.1:6379> Hset user name tiger age 18 gender man
(integer) 3
127.0.0.1:6379> Hlen user	# 获取user的长度
(integer) 3

 
 

判断hash中是否存在一个field:Hexists key field

127.0.0.1:6379> Hgetall user
1) "name"
2) "tiger"
3) "age"
4) "18"
5) "gender"
6) "man"
127.0.0.1:6379> Hexists user name		# 判断user中是否有name
(integer) 1		# 1表示有
127.0.0.1:6379> Hexists user hobby		# 判断user中是否有hobby
(integer) 0		# 0表示没有

 
 


只获取field :Hkeys key
只获取value:Hvals key

127.0.0.1:6379> Hgetall user
1) "name"
2) "tiger"
3) "age"
4) "18"
5) "gender"
6) "man"
127.0.0.1:6379> Hkeys user		# 只获取user中的键
1) "name"
2) "age"
3) "gender"
127.0.0.1:6379> Hvals user		# 只获取user中的值
1) "tiger"
2) "18"
3) "man"

 
 

自增或自减:Hincrby key field count

127.0.0.1:6379> Hget user age
"18"
127.0.0.1:6379> Hincrby user age 1		# age加1
(integer) 19
127.0.0.1:6379> Hget user age
"19"
127.0.0.1:6379> Hincrby user age -3		# age减3
(integer) 16
127.0.0.1:6379> Hget user age
"16"

 
 

如果field存在则不会执行:Hsetnx key field value

127.0.0.1:6379> Hsetnx user name studioustiger	# 向user中添加一个name
(integer) 0		# 0表示失败
127.0.0.1:6379> Hsetnx user hobby sleep			# 向user中添加一个hobby
(integer) 1		# 1 表示成功
127.0.0.1:6379> Hgetall user					# 我们可以发现确实已经添加进来了
1) "name"
2) "tiger"
3) "age"
4) "16"
5) "gender"
6) "man"
7) "hobby"
8) "sleep"

 
 

应用:hash可以很好的存储实体类(对象)中的信息,例如:Hset user:1 name tiger age 18 gender man


6、Zset 有序集合类型的讲解

Zset与set的区别在于,zset 可以为每一个元素设置一个score,用户根据score对元素进行排序


添加:Zadd key01 score01 value01 key02 score02 value02 ...
打印:Zrange key 0 -1

127.0.0.1:6379> Zadd age 18 tiger 15 mark 8 konkey 23 zhang	#添加元素,并给每一个元素设置score
(integer) 4
127.0.0.1:6379> Zrange age 0 -1		# 打印所有元素,默认为升序
1) "konkey"
2) "mark"
3) "tiger"
4) "zhang"

 
 


升序(负无穷,正无穷):Zrangebyscore key -inf +inf
升序(负无穷,正无穷)带着score:Zrangebyscore key -inf +inf withscore

127.0.0.1:6379> Zrangebyscore age -inf +inf			# 升序排列
1) "konkey"
2) "mark"
3) "tiger"
4) "zhang"
127.0.0.1:6379> Zrangebyscore age 18 23				# 指定范围的升序排列
1) "tiger"
2) "zhang"
127.0.0.1:6379> Zrangebyscore age 18 23 withscores	# 指定范围的升序排列,并带着score
1) "tiger"
2) "18"
3) "zhang"	# value
4) "23"		# score

 
 

④ 降序:Zrevrange key 0 -1

127.0.0.1:6379> Zrevrange age 0 -1				# 所有元素降序排序
1) "zhang"
2) "tiger"
3) "mark"
4) "konkey"
127.0.0.1:6379> Zrevrange age 0 -1 withscores	# 所有元素降序排序,并且带着score
1) "zhang"
2) "23"
3) "tiger"
4) "18"
5) "mark"
6) "15"
7) "konkey"
8) "8"

 
 

⑤ 移除元素:Zrem key value

127.0.0.1:6379> Zrange age 0 -1
1) "konkey"
2) "mark"
3) "tiger"
4) "zhang"
127.0.0.1:6379> Zrem age zhang mark		# 移除age中的zhang和mark
(integer) 2
127.0.0.1:6379> Zrange age 0 -1			# 确实已将移除了
1) "konkey"
2) "tiger"

 
 

⑥ 获取集合中的个数:Zcard key

127.0.0.1:6379> Zrange age 0 -1
1) "konkey"
2) "tiger"
127.0.0.1:6379> Zcard age		# 获取age中元素的个数
(integer) 2			# age中有2个元素

 
 

⑦ 获取指定区间的元素个数:Zcount key min max

127.0.0.1:6379> Zrange age 0 -1
1) "konkey"
2) "mark"
3) "tiger"
4) "zhang"
127.0.0.1:6379> Zcount age 15 23   # 获取score在[15,23]期间的元素个数
(integer) 3

 
 

思路案例:
成绩表排序
工资表排序

普通消息 的权重为1
重要消息 的权重为2

排行榜


三、geospatial 地理位置的详解

1、简介

查询城市经纬度的网站:https://jingweidu.bmcx.com/

注意:
有效的经度从-180度180度
有效的纬度从-85.05112878度85.05112878度
当坐标位置超出上述指定范围时,该命令将会返回一个错误。


2、命令

① 添加一个或多个地理空间位置到sorted set

geoadd key 经度 纬度 城市[ 经度 纬度 城市...]

127.0.0.1:6379> geoadd cn:city 116.75199 36.55358 jinan			# 济南
(integer) 1
127.0.0.1:6379> geoadd cn:city 114.49339 36.61853 handan		# 邯郸
(integer) 1
127.0.0.1:6379> geoadd cn:city 115.98847 36.43452 liaocheng		# 聊城
(integer) 1
127.0.0.1:6379> geoadd cn:city 117.86172 36.49473 zibo			# 淄博
(integer) 1
127.0.0.1:6379> geoadd cn:city 119.16607 36.65458 weifang		# 潍坊
(integer) 1
127.0.0.1:6379> geoadd cn:city 121.26757 37.49794 weihai		# 威海
(integer) 1
127.0.0.1:6379> geoadd cn:city 122.12348 37.50212 yantai		# 烟台
(integer) 1
127.0.0.1:6379> geoadd cn:city 116.29941 37.45079 dezhou		# 德州
(integer) 1
127.0.0.1:6379> geoadd cn:city 118.02279 37.42726 binzhou		# 滨州
(integer) 1
127.0.0.1:6379> geoadd cn:city 118.58215 37.44878 dongying		# 东营
(integer) 1
127.0.0.1:6379> geoadd cn:city 116.59649 35.4082 jining			# 济宁
(integer) 1
127.0.0.1:6379> geoadd cn:city 118.40184 35.08729 linyi			# 临沂
(integer) 1
127.0.0.1:6379> geoadd cn:city 119.46242 35.42545 rizhao		# 日照
(integer) 1
127.0.0.1:6379> geoadd cn:city 117.4613 35.09963 zaozhuang		# 枣庄
(integer) 1

 
 

② 返回一个标准的地理空间的Geohash字符串

geohash key 城市 [城市...]

127.0.0.1:6379> geohash cn:city binzhou dongying  # 获取滨州和东营的hash字符串
1) "wweuvtmtd70"
2) "wwsm43kfuq0"
# 因为滨州和东营的经纬度本身就很接近,所以其经纬度所对应的hash字符串也是比较接近的

 
 

③ 返回地理空间的经纬度

geopos key 城市 [城市...]

127.0.0.1:6379> geopos cn:city jinan linyi  # 获取济南和临沂的经纬度
1) 1) "116.75199061632156372"	# 济南的经度
   2) "36.55358010603453778"	# 济南的纬度
2) 1) "118.40183883905410767"   # 临沂的经度
   2) "35.08728954033782799"	# 临沂的纬度

 
 

④ 返回两个地理空间之间的距离

geodist key 城市1 城市2 [unit]

会利用某种算法,根据经纬度求出两地的直线距离

127.0.0.1:6379> geodist cn:city jinan linyi km	# 获取济南的临沂的直线距离(km)
"220.7609"
127.0.0.1:6379> geodist cn:city jinan zibo km   # 获取济南的淄博的直线距离(km)
"99.4054"

 
 

unit的取值如下:
m 表示单位为米。
km 表示单位为千米。
mi 表示单位为英里。
ft 表示单位为英尺。

⑤ 查询指定半径内所有的地理空间元素的集合。

georadius key 经度 纬度 半径 m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

# 查询以(经度为116,纬度为36)为圆心,100km为半径,cn:city所包含的城市
127.0.0.1:6379> georadius cn:city 116 36 100 km
1) "liaocheng"	# 聊城
2) "jinan"		# 济南
3) "jining"		济宁

 
 

⑥ 查询指定半径内匹配到的最大距离的一个地理空间元素。

georadiusbymember key 城市 半径 m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count]

# 查询以济南为中心,方圆300km内的城市
127.0.0.1:6379> georadiusbymember cn:city jinan 300 km
 1) "nandan"
 2) "jining"
 3) "zaozhuang"
 4) "liaocheng"
 5) "zibo"
 6) "jinan"
 7) "dezhou"
 8) "binzhou"
 9) "linyi"
10) "rizhao"
11) "weifang"
12) "dongying"

 
 

⑦ 查看所有的城市

Zrange key 0 -1

127.0.0.1:6379> zrange cn:city 0 -1		# 查看cn:city中的所有城市
 1) "nandan"
 2) "jining"
 3) "zaozhuang"
 4) "liaocheng"
 5) "zibo"
 6) "jinan"
 7) "linyi"
 8) "rizhao"
 9) "weifang"
10) "qingdao"
11) "dezhou"
12) "binzhou"
13) "dongying"
14) "weihai"
15) "yantai"

 
 

⑧ 将指定城市移除出去

Zrem key 城市1 城市2 ...

# 将邯郸、东营和日照移除
127.0.0.1:6379> zrem cn:city nandan dongying rizhao liaochneg 
(integer) 3
127.0.0.1:6379> zrange cn:city 0 -1		# 确实已经移除了
 1) "jining"
 2) "zaozhuang"
 3) "liaocheng"
 4) "zibo"
 5) "jinan"
 6) "linyi"
 7) "weifang"
 8) "qingdao"
 9) "dezhou"
10) "binzhou"
11) "weihai"
12) "yantai"

 
 

四、hyperloglog 基数统计的详解

1、简介

什么事基数,我们可以可以认为是一组数据中不重复的个数,我们称之为该组数据的基数。

在开发中,我们可以通过基数解决用户访问量的(user view)问题,一个用户访问多次,我们依然认为是一次访问,那么使用基数我们就可以很好的解决这个问题。

此时有人又要问了,那我为什么要是有Redis中的Hyperloglog呢?难道使用set集合它不香吗?我要告诉你的是太还真的不香。

set的所占的空间太大了,而我们使用hyperloglog存储2^64歌不同的元素只需要12KB的内存(大数据情况下有0.81%的错误率)。

2、命令

① 将所有元素参数添加到 HyperLogLog 数据结构中
PFadd key element [element ...]

# 向hyperloglog中存入如下歌元素,我们可知它的基数为7
127.0.0.1:6379> pfadd elem a b c d e f g g g g g
(integer) 1

 
 

② 返回给定 HyperLogLog 的基数估算值
PFcount key [key ...]

127.0.0.1:6379> pfadd elem a b c d e f g g g g g
(integer) 1
127.0.0.1:6379> pfcount elem	# 获取elem中的基数
(integer) 7						# 7明显是正确的

③ 将多个 HyperLogLog 合并为一个 HyperLogLog
PFmerge destkey sourcekey [sourcekey ...]

127.0.0.1:6379> pfadd elem1 a b c d e e f f		# 向elem1中存入a b c d e e f f
(integer) 1
127.0.0.1:6379> pfcount elem1					# 很明显,elem1的基数确实是6
(integer) 6
127.0.0.1:6379> pfadd elem2 t h j k l f			# 向elem2中存入t h j k l f
(integer) 1					
127.0.0.1:6379> pfcount elem2					# 很明显,elem2的基数确实是6
(integer) 6
127.0.0.1:6379> pfmerge elem3 elem1 elem2		# 将elem1和elem2进行合并成elem3
OK
127.0.0.1:6379> pfcount elem3					# 很明显,elem3的基数确实是11
(integer) 11

 
 

五、bitmap 位图场景的详解

1、简介

bitmap是使用位存储实现的数据结构,所以说,bitmap的效率是十分的乐观的额。但是bitmap的应用场景又有那些呢?

凡是具有对立性的信息,我们都可以使用bitmap进行存储。例如:我们可以我们可以统计用户是活跃情况、用户的登录情况、打卡情况。

我们在进行存储的使用,对于状态我们只需要使用使用0和1进行表示即可。

2、命令

① 向bitmap中存值
setbit key offset value

# 下面我们设置一周的打卡情况(1表示打卡,0表示未打卡)
127.0.0.1:6379> setbit clockIn 1 1	# 周一:打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 2 0	# 周二:未打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 3 0	# 周三:未打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 4 1	# 周四:打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 5 1	# 周五:打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 6 1	# 周六:打卡
(integer) 0
127.0.0.1:6379> setbit clockIn 0 0	# 周日:未打卡
(integer) 0

 
 

② 从bitmap中取值
getbit key offset

127.0.0.1:6379> getbit clockIn 4	# 获取周四的打卡情况
(integer) 1		# 周四打卡
127.0.0.1:6379> getbit clockIn 0	# 获取周日的打卡情况
(integer) 0		# 周日未打卡

 
 

③ 统计bitmap中值为1的数量
bitcount key [start] [end]

127.0.0.1:6379> bitcount clockIn		# 统计bitmap中值为1的数量
(integer) 4		# 很明显,周一到周日确实是4次打开

 
 



六、redis中的事务

1、简介

Redis 事务的本质
①Redis的事务就是一组命令的集合。
②一个事务中所有的命令都会被序列化,并在事务执行的过程中按照顺序执行。
③Redis的事务具有一次性、顺序性、排他性。

Redis与MySQL的区别
在关系型数据库(如:mysql)中事务之间是有隔离界别的概念的,但是在Redis中是没有隔离界别的概念的。在Redis中所有的命令在事务中并没有被直接执行,而是要等待执行命令才会执行。

在关系型数据库中事务是具有ACID原则的,其中的原子性是指:要么都执行成功,要么都执行失败。但是在Redis中事务是不具有原子性的,但是Redis的单条命令是具有原子性的。

2、命令

① 开启事务
multi

② 命令入队
一些命令...

③ 执行事务
exec

④ 取消事务
discard

正常执行事务

127.0.0.1:6379> multi				# 开启事务
OK
127.0.0.1:6379(TX)> set name tiger	# 命令1入队
QUEUED
127.0.0.1:6379(TX)> set age 18		# 命令2入队
QUEUED
127.0.0.1:6379(TX)> get name		# 命令3入队
QUEUED
127.0.0.1:6379(TX)> get age			# 命令4入队
QUEUED
127.0.0.1:6379(TX)> exec			# 执行事务
1) OK
2) OK
3) "tiger"
4) "18"

 
 

取消事务执行

127.0.0.1:6379> multi							# 开启事务
OK
127.0.0.1:6379(TX)> set name2 studioustiger		# 命令1
QUEUED
127.0.0.1:6379(TX)> get name2					# 命令2
QUEUED
127.0.0.1:6379(TX)> discard						#取消事务的执行
OK
127.0.0.1:6379> get name2						# 命令1确实没有被执行
(nil)

 
 
3、注意

编译时异常(入队命令错误)时,那么事务中的所有的事务都不会执行

127.0.0.1:6379> multi			# 开启事务
OK
127.0.0.1:6379(TX)> set name hanjiang		# 命令1
QUEUED
127.0.0.1:6379(TX)> getsss name		# 命令2(没有getss命令)
(error) ERR unknown command `getsss`, with args beginning with: `name`,
127.0.0.1:6379(TX)> set age 18		# 命令3
QUEUED
127.0.0.1:6379(TX)> get age			# 命令4
QUEUED
127.0.0.1:6379(TX)> exec			# 执行事务
# (错误)由于以前的错误,已放弃EXECABORT事务
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get name			# 命令1确实没有执行
(nil)
127.0.0.1:6379> get age				# 命令3确实没有执行
(nil)

 
 

运行时异常(命令存在语法错误)时,那么只有语法错误的命令不会执行,并且胡抛出异常

127.0.0.1:6379> set age 18yearsOld			# 设置一个字符串类型的age
OK
127.0.0.1:6379> multi						# 开启事务
OK
127.0.0.1:6379(TX)> incr age				# 命令1(很明显语法错误,字符串不能自增)
QUEUED
127.0.0.1:6379(TX)> set name zhangsan		# 命令2
QUEUED
127.0.0.1:6379(TX)> set hobby sleep			# 命令3
QUEUED
127.0.0.1:6379(TX)> get name				# 命令4
QUEUED
127.0.0.1:6379(TX)> get hobby				# 命令5
QUEUED
127.0.0.1:6379(TX)> exec
# (错误) 值不是整型,或者越界
1) (error) ERR value is not an integer or out of range
2) OK			# 命令2 执行成功
3) OK			# 命令3 执行成功
4) "zhangsan"	# 命令4 执行成功
5) "sleep"		# 命令5 执行成功

 
 



七、watch 实现乐观锁

1、简介

其实我们在mybatis-plus阶段已经学过乐观锁了,在这里我就不在过多的赘述了,只作简单的介绍。

在数据库中实现防止脏数据的方式有两种,一种是悲观锁,另一种是乐观锁。
悲观锁:认为进行数据操作完成前,数据都会被提前修改过,所以每次操都会加上线程锁。
乐观锁:认为进行数据操作完成前,数据都不会被提前修改过,所以每次操都不会加上线程锁。

既然乐观锁不会线程程锁,那么如何保证数据不会是脏数据呢?我们可以使用一个version字段进行判断。规定:数据被修改时,其对应的version必须加一。这样我们只需要在更新前获取依次version,执行更新是比对当前version是否发生了改变,只有前后的version保持一致,才会执行操作。

在mysql中,上述的规定是很容易实现的,但是在Redis中又该如何实现呢?下面我们来解决这个问题。

2、命令

在Redis中我们可以给一个数据加上监视(watch),当一个数据被加上watch后,当前数据被其他线程修改了,那么watch后的 事务将不会被执行。我们可以认为当一个数据被加上watch后,就相当于给他加上一个version且version=1,每当该数据被修改,那么其version会+1。

给数据加上监视的命令
watch key

① 线程安全时

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379> watch money				# 给money加上监视
OK
127.0.0.1:6379> multi					# 开启事务
OK
127.0.0.1:6379(TX)> incrby money 10		# 对money进行加10
QUEUED
127.0.0.1:6379(TX)> get money			# 获取money
QUEUED
127.0.0.1:6379(TX)> exec				# 提交事务
1) (integer) 110						# 很明显,事务执行成功
2) "110"

 
 

② 线程不安全时

127.0.0.1:6379> get money
"100"
127.0.0.1:6379> watch money				# 给money加上监视
OK
127.0.0.1:6379> decrby money 20			# 在加上监视后money数据被修改了
(integer) 80
127.0.0.1:6379> multi					# 开启事务
OK
127.0.0.1:6379(TX)> incrby money 10		# 命令1
QUEUED
127.0.0.1:6379(TX)> get money			# 命令2
QUEUED
127.0.0.1:6379(TX)> exec				# 提交事务
(nil)									# 很明显事务并别有提交成功



八、jedis 操作 Redis

注意:我们是基于maven项目进行的,Linux使用的是本地的Linux虚拟机。

1、java连接redis(☆)

① 导入相关依赖

<dependencies>
    <!-- jedis依赖 -->
    <dependency>
        <groupId>redis.clients</groupId>
        <artifactId>jedis</artifactId>
        <version>3.5.2</version>
    </dependency>
    <!-- fastjson依赖 -->
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>fastjson</artifactId>
        <version>1.2.78</version>
    </dependency>
    <!-- junit -->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.13.2</version>
        <scope>test</scope>
    </dependency>

</dependencies>

② 编写测试类

@Test
public void t1(){
    //1、创建一个jedis对象
    Jedis jedis = new Jedis("192.168.174.128", 6379);
    System.out.printf(jedis.ping());
}

 
 

你可能会遇到的错误
redis.clients.jedis.exceptions.JedisConnectionException: Failed connecting to 192.168.174.128:6379
...
Caused by: java.net.SocketTimeoutException: connect timed out

解决方法
① 关闭Linux防火墙和设置禁止开启自启

[root@localhost bin]# systemctl stop firewalld.service		# 关闭防护墙
[root@localhost bin]# systemctl disable firewalld.service	# 禁止开启自启
Removed symlink /etc/systemd/system/multi-user.target.wants/firewalld.service.
Removed symlink /etc/systemd/system/dbus-org.fedoraproject.FirewallD1.service.

 
 
<

② 修改redis.conf配置文件,注释掉底75行

72 # IF YOU ARE SURE YOU WANT YOUR INSTANCE TO LISTEN TO ALL THE INTERFACES
73 # JUST COMMENT OUT THE FOLLOWING LINE.
74 # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
75 # bind 127.0.0.1 -::1			##75行的内容只是掉,那么任何IP都可以访问了

 
 

③ 修改redis.conf配置文件,将94行yes改为no

90 # By default protected mode is enabled. You should disable it only if
91 # you are sure you want clients from other hosts to connect to Redis
92 # even if no authentication is configured, nor a specific set of interfaces
93 # are explicitly listed using the "bind" directive.
94 protected-mode no    # 将原本的yes改为no

 
 

连接成功
在这里插入图片描述

3、实践

我们上面所讲的命令在Java中通过jedis对象都可以使用,所以在这里我就简单的使用几个,给大家证明一下。

① 简单的指令测试

@Test
public void t1(){
    //1、创建一个jedis对象
    Jedis jedis = new Jedis("192.168.174.128", 6379);
<span class="token comment">//我们之前所学的所有的指令在这里都是可以使用的,所以前面的内容真的很重要</span>
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>jedis<span class="token punctuation">.</span><span class="token function">ping</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">flushDB</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>								# 清空当前的数据库
<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"---------------------"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"studioustiger"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>				# set 命令
jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"age"</span><span class="token punctuation">,</span><span class="token string">"18"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> mget <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">mget</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"age"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	# mget 命令
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> val <span class="token operator">:</span> mget<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

<span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"----------------------"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">incrBy</span><span class="token punctuation">(</span><span class="token string">"age"</span><span class="token punctuation">,</span><span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>							# incrby 命令
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> mget2 <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">mget</span><span class="token punctuation">(</span><span class="token string">"name"</span><span class="token punctuation">,</span> <span class="token string">"age"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	# nget 命令
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">String</span> val <span class="token operator">:</span> mget2<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>val<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>

}

我们可以看到,结果没有任何问题
在这里插入图片描述

② 乐观锁:线程安全时
值得注意的是,当对某一个元素开启事务之后,在事务提交前我们都是不能使用Jedis进行事务操作的,而是要使用Transaction进行事务操作。

@Test
public void t2(){
    Jedis jedis = new Jedis("192.168.174.128", 6379);
    jedis.flushDB();
jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">,</span><span class="token string">"100"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">watch</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>						# 对money进行监控

<span class="token class-name">Transaction</span> transaction <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">multi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	# 开启事务
transaction<span class="token punctuation">.</span><span class="token function">incrBy</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">,</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
transaction<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> exec <span class="token operator">=</span> transaction<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>		# 提交事务

<span class="token keyword">if</span><span class="token punctuation">(</span>exec<span class="token operator">==</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"null"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{<!-- --></span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Object</span> o <span class="token operator">:</span> exec<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>o<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

在这里插入图片描述

③ 乐观锁:线程不安全时

@Test
public void t3(){
    Jedis jedis = new Jedis("192.168.174.128", 6379);
    jedis.flushDB();
jedis<span class="token punctuation">.</span><span class="token function">set</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">,</span><span class="token string">"100"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
jedis<span class="token punctuation">.</span><span class="token function">watch</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>						# 对money开启监控
jedis<span class="token punctuation">.</span><span class="token function">decrBy</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">,</span><span class="token number">20</span><span class="token punctuation">)</span><span class="token punctuation">;</span>					# 在事务外money被修改了

<span class="token class-name">Transaction</span> transaction <span class="token operator">=</span> jedis<span class="token punctuation">.</span><span class="token function">multi</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>	# 开启事务
transaction<span class="token punctuation">.</span><span class="token function">incrBy</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">,</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
transaction<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token string">"money"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> exec <span class="token operator">=</span> transaction<span class="token punctuation">.</span><span class="token function">exec</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>		# 提交事务

<span class="token keyword">if</span><span class="token punctuation">(</span>exec<span class="token operator">==</span><span class="token keyword">null</span><span class="token punctuation">)</span><span class="token punctuation">{<!-- --></span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">"null"</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span><span class="token keyword">else</span><span class="token punctuation">{<!-- --></span>
    <span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Object</span> o <span class="token operator">:</span> exec<span class="token punctuation">)</span> <span class="token punctuation">{<!-- --></span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>o<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>

}

在这里插入图片描述

redis-命令的官方文档:https://www.redis.net.cn/order/3685.html


  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值