redis学习

2021/4/12 19:26:57

本文主要是介绍redis学习,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

redis学习

基本redis命令和笔记
观看的视频是《狂神学redis》自己整理的redis命令和基本知识点
感谢!!!
PDF版本在资源文件中,大家下载就可以!!!

一 基本命令

1.DBSIZE查看数据库中的数据总量

127.0.0.1:6379[1]> select 12
OK
127.0.0.1:6379[12]> DBSIZE
(integer) 0
127.0.0.1:6379[12]> 

2.select 数字 选择切换几号的数据库

[root@localhost bin]# redis-cli -p 6379
127.0.0.1:6379> ping
PONG
127.0.0.1:6379> select 1
OK
127.0.0.1:6379[1]> set age 23
OK
127.0.0.1:6379[1]> get age
"23"
127.0.0.1:6379[1]> 

# Set the number of databases. The default database is DB 0, you can select
# a different one on a per-connection basis using SELECT <dbid> where
# dbid is a number between 0 and 'databases'-1
databases 16
默认的数据库总共为16个  0~15

3.get 和set

127.0.0.1:6379[1]> set age 23
OK
127.0.0.1:6379[1]> get age
"23"
127.0.0.1:6379[1]> 

4.keys *

产看当前数据库的所有key

127.0.0.1:6379[12]> keys *
(empty array)
127.0.0.1:6379[12]> set name xiaoming
OK
127.0.0.1:6379[12]> keys *
1) "name"
127.0.0.1:6379[12]> 

5.flushdb

清空当前数据库

127.0.0.1:6379[12]> set name xiaoming
OK
127.0.0.1:6379[12]> keys *
1) "name"
127.0.0.1:6379[12]> flushdb
OK
127.0.0.1:6379[12]> keys *
(empty array)
127.0.0.1:6379[12]> 

6.FLUSHALL

清除所有的数据库内容

127.0.0.1:6379[12]> FLUSHALL
OK
127.0.0.1:6379[12]> select 0
OK
127.0.0.1:6379> DBSIZE
(integer) 0
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> 

7.move和exists

move 将key 及其所对应的value 移到其他指定的库当中

EXISTS key查看指定的key是否存在 为1 存在

127.0.0.1:6379> FLUSHALL
OK
127.0.0.1:6379> select 0
OK
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> set name xiaowang
OK
127.0.0.1:6379> EXISTS name
(integer) 1
127.0.0.1:6379> move name 1
(integer) 1
127.0.0.1:6379> keys *
(empty array)
127.0.0.1:6379> 

  1. ttl 和 expire

    ttl 查看当前key的生存时间

    expire key second 设置key生存second秒 (适合缓存数据 和用户的信息停留多久)

    127.0.0.1:6379> set name xiaohua
    OK
    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> exists name
    (integer) 0
    127.0.0.1:6379> 
    
    

    9.type 和 del

    type查看key的value的类型

    del删除指定的 key-value

    127.0.0.1:6379> set sex girl
    OK
    127.0.0.1:6379> type sex
    string
    127.0.0.1:6379> set age 21
    OK
    127.0.0.1:6379> type age
    string
    127.0.0.1:6379> del sex
    (integer) 1
    127.0.0.1:6379> exists sex
    (integer) 0
    127.0.0.1:6379> 
    
    

二 数据类型结构

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-VxLhvrWy-1618203092691)(D:\MyAppClass\QQ\Files\2811085093\FileRecv\MobileFile\IMG_0684(20210410-134132)].PNG)

基本类型

String类型

127.0.0.1:6379> set key1 "xiaohui"
OK
127.0.0.1:6379> setrange key1 3 xixi   #替换某个范围上的值 相当于 replace
(integer) 7
127.0.0.1:6379> get key1               
"xiaxixi"
127.0.0.1:6379> getrange key1 2 3      #获取某个范围上的值 substring
"ax"
127.0.0.1:6379> setrange key1 2 xihuanni
(integer) 10
127.0.0.1:6379> get key1
"xixihuanni"
1.0.1:6379> 

127.0.0.1:6379> set n 1
OK
127.0.0.1:6379> get n
"1"
127.0.0.1:6379> incr n       #自增1
(integer) 2
127.0.0.1:6379> decr n       #自减1
(integer) 1
127.0.0.1:6379> get n
"1"
127.0.0.1:6379> type n        #类型
string
127.0.0.1:6379> incr n
(integer) 2
127.0.0.1:6379> incrby n 4    #指定自增的步长
(integer) 6
127.0.0.1:6379> decrby n 3     #指定自减的步长
(integer) 3

127.0.0.1:6379> keys *
1) "n"
2) "key1"
127.0.0.1:6379> get key1
"xixihuanni"
127.0.0.1:6379> append key1 111    #追加字符串
(integer) 13
127.0.0.1:6379> get key1
"xixihuanni111"

127.0.0.1:6379> strlen key1       #字符串的长度
(integer) 13

127.0.0.1:6379> set name xiaohui
OK
127.0.0.1:6379> expire name 12    #设置生存时间,过期时间
(integer) 1
127.0.0.1:6379> ttl name           #查看过期时间
(integer) 10

127.0.0.1:6379> ttl name
(integer) 2
127.0.0.1:6379> get name
(nil)


127.0.0.1:6379> get key1
"xixihuanni111"
127.0.0.1:6379> getrange key1 1 4        #获取某一个范围上的值
"ixih"

127.0.0.1:6379> setrange key1 3 xihuan       #设置key的某一个范围的值
(integer) 13
127.0.0.1:6379> 

127.0.0.1:6379> setex age 12 45    #设置值的同时设置expire过期的时间
OK
127.0.0.1:6379> get age
"45"
127.0.0.1:6379> ttl age          #查看过期时间
(integer) 5
127.0.0.1:6379> ttl age
(integer) 1
127.0.0.1:6379> get age
(nil)
127.0.0.1:6379> 

127.0.0.1:6379> setnx age 23     #如果不存在就设置
(integer) 1
127.0.0.1:6379> get age
"23"
127.0.0.1:6379> setnx age 34      #因为原来存在了 所以设置失败
(integer) 0
127.0.0.1:6379> get age           #获取的仍然是原来的值
"23"
127.0.0.1:6379> 

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  #批量的设值  空格分隔就好
OK
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> mget k1 k2 k3   #批量的获取
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 vv1 k4 v4       #如果不存在则批量设置
(integer) 0                            #注意msetnx为原子的,一个不成功都不成功
127.0.0.1:6379> get k1
"v1"
127.0.0.1:6379> get k4
(nil)


127.0.0.1:6379> mset k1 vv1 k2 vv2  #mset批量的设置 如果之前存在的键值就覆盖
OK
127.0.0.1:6379> get k1
"vv1"
127.0.0.1:6379> 


127.0.0.1:6379> getset key6 45   #先获取再赋值 返回之前的值
(nil)
127.0.0.1:6379> get key6
"45"

127.0.0.1:6379> getset key6 47
"45"
127.0.0.1:6379> get key6
"47"
127.0.0.1:6379> 

127.0.0.1:6379> mset user:id 23 user:name xioahua
OK
#类似于设置对象的属性 并且获取
127.0.0.1:6379> get user:id
"23"
127.0.0.1:6379> 

··················

List(实际上是一个链表了 既可以做栈 也可以做队列)

所有的list命令都是l开头

lpush 放头部

lrange 取 (0 -1表示全部)

rpush 放尾部

lpop移除第一

rpop 移除 倒数一

lindex下表取值

llen获取长度

lrem 移除

ltrim修剪 保留一部分元素(原地修改)

rpoplpush移除列表的最后一个元素并添加到另一个列表

lset 更新已有下表的值 (不存在报错)

linsert 在某一个key前或后插入值

linsert 命令用于在列表的元素前或者后插入元素。当指定元素不存在于列表中时,不执行任何操作,当列表不存在时,被视为空列表,不执行任何操作。

127.0.0.1:6379> lrange list 0 -1
1) "3333"
2) "56"

插入到 在前后 哪个key前后  插入的值
127.0.0.1:6379> linsert list before 56 44
(integer) 3

127.0.0.1:6379> lrange list 0 -1
1) "3333"
2) "44"
3) "56"
127.0.0.1:6379> 

127.0.0.1:6379> lpush list 23    放入
(integer) 1
127.0.0.1:6379> lpush list 34    
(integer) 2
      
127.0.0.1:6379> lrange list 0 -1   取出全部查看
1) "34"
2) "23"
  
127.0.0.1:6379> lpop list      取出最前面的元素
"34"
127.0.0.1:6379> lrange list 0 -1  查看所有
1) "23"
127.0.0.1:6379> lpush list 56
(integer) 2
127.0.0.1:6379> rpop list   从下面弹出
"23"

127.0.0.1:6379> lrange list 0 -1
1) "56"

127.0.0.1:6379> lpush list 3333
(integer) 2

127.0.0.1:6379> lindex list 1  根据下表获取值 从0开始
"56"

127.0.0.1:6379> lrange list  0 -1
1) "3333"
2) "56"
127.0.0.1:6379> 
127.0.0.1:6379> lrange list 0 -1
1) "3333"
2) "44"
3) "56"
127.0.0.1:6379> ltrim list 0 1   #原地修剪 截取部分的值
OK
127.0.0.1:6379> lrange list 0 -1
1) "3333"
2) "44"
127.0.0.1:6379> 

127.0.0.1:6379> lrange list 0 -1
1) "3333"
2) "44"
127.0.0.1:6379> lpush list2 2345
(integer) 1

127.0.0.1:6379> rpoplpush list list2  前面的尾巴切掉 放到后面的头头
"44"
127.0.0.1:6379> lrange list 0 -1
1) "3333"
127.0.0.1:6379> lrange list2 0 -1
1) "44"
2) "2345"
127.0.0.1:6379> 

set(值不能重复)

sadd 添加

smenbers成员查看

sismember 是否存在某个成员

scard 获取set元素的个数

srem 移除元素

srandmember随机选择成员

spop随机弹出元素

smove 将某一个set的元素移到另一个set

sdiff查找两个集合的差集

sinter查找两个集合的交集

sunion求两个集合的并集

127.0.0.1:6379> clear
127.0.0.1:6379> sadd set1 34      添加元素到集合
(integer) 1
127.0.0.1:6379> sadd set1 45
(integer) 1
127.0.0.1:6379> sadd set1 45
(integer) 0
127.0.0.1:6379> smembers set1     查看所有的成员元素
1) "34"
2) "45"
127.0.0.1:6379> sismember set1 45   查看是否存在某一个成员元素
(integer) 1
127.0.0.1:6379> scard set1      查看集合元素的个数
(integer) 2
127.0.0.1:6379> srem set1 45   移除某一个元素
(integer) 1
127.0.0.1:6379> scard set1
(integer) 1
127.0.0.1:6379> sadd set1 78
(integer) 1
127.0.0.1:6379> sadd set1 700
(integer) 1
127.0.0.1:6379> scard set1
(integer) 3
127.0.0.1:6379> smembers set1
1) "34"
2) "78"
3) "700"
127.0.0.1:6379> sismember set1 34       是否包含某一个元素
(integer) 1
127.0.0.1:6379> sismember set1 3
(integer) 0
127.0.0.1:6379> spop set1    随机删除一个元素
"78"
127.0.0.1:6379> spop set1
"34"
127.0.0.1:6379> srem set1 700
(integer) 1
127.0.0.1:6379> scard set1
(integer) 0
127.0.0.1:6379> 

127.0.0.1:6379> sadd set1 11
(integer) 1
127.0.0.1:6379> sadd set1 22
(integer) 1
127.0.0.1:6379> sadd set1 33
(integer) 1
127.0.0.1:6379> sadd set2 33
(integer) 1
127.0.0.1:6379> sadd set2 44
(integer) 1
127.0.0.1:6379> sadd set2 11
(integer) 1
127.0.0.1:6379> sunion set1 set2   集合并
1) "11"
2) "22"
3) "33"
4) "44"
127.0.0.1:6379> sdiff set1 set2       集合差
1) "22"
127.0.0.1:6379> sinter set1 set2      集合交
1) "11"
2) "33"
127.0.0.1:6379> 


127.0.0.1:6379> smembers set1
1) "11"
2) "22"
3) "33"
127.0.0.1:6379> smove set1 set2 22   两个集合间移动元素
(integer) 1
127.0.0.1:6379> smembers set2
1) "11"
2) "22"
3) "33"
4) "44"
127.0.0.1:6379> 


Hash

方法跟string差不多

hash集合中的-元素为map类型 或者 key为某一个hash的集合 ---- field value值是一个map作为集合的值

127.0.0.1:6379> hset hash1 str woaini
(integer) 1
127.0.0.1:6379> type hash1
hash
127.0.0.1:6379> 

h开头的命令

hset

hget

hmset批量的设置值 可被覆盖

hmget

hgetall获取一个key的所有的值

hdel删除指定字段的值

hlen获取长度hex

hexists判断是否存在元素字段

hkeys获取所有的字段的key

hincrby

hdecrby

放入值
127.0.0.1:6379> hset hash1 key1 value1
(integer) 1
127.0.0.1:6379> hset hash1 key2 value2
(integer) 1

获取值
127.0.0.1:6379> hget hash1 key1
"value1"

批量放入
127.0.0.1:6379> hmset hash1 key3 value3 key4 value4
OK

获取全部的key-value
127.0.0.1:6379> hgetall hash1
1) "key1"
2) "value1"
3) "key2"
4) "value2"
5) "key3"
6) "value3"
7) "key4"
8) "value4"

求所有对应的元素字段的个数 key --value 的总共有多少对
127.0.0.1:6379> hlen hash1
(integer) 4

判断是否存在某一个key和相应的value
127.0.0.1:6379> hexists hash1 key2
(integer) 1

获取key的集合
127.0.0.1:6379> hkeys hash1
1) "key1"
2) "key2"
3) "key3"
4) "key4"

删除某一个key和value
127.0.0.1:6379> hdel hash1 key1
(integer) 1
127.0.0.1:6379> hset hash1 key1 45
(integer) 1
127.0.0.1:6379> hgetall hash1
1) "key2"
2) "value2"
3) "key3"
4) "value3"
5) "key4"
6) "value4"
7) "key1"
8) "45"

指定步长的增减key所对的value
127.0.0.1:6379> hincrby hash1 key1 2
(integer) 47

127.0.0.1:6379> hgetall hash1
1) "key2"
2) "value2"
3) "key3"
4) "value3"
5) "key4"
6) "value4"
7) "key1"
8) "47"
127.0.0.1:6379> 

zset

根据某个标志进行排序有序的集合

zrange

zrangebyscore (-inf 负无穷 +inf正无穷)

zadd

zrem

zcard

zrevrange

zcount

127.0.0.1:6379> zadd salary 1 5000
(integer) 1
127.0.0.1:6379> zadd salary 2 6000        添加
(integer) 1 
127.0.0.1:6379> zadd salary 3 8000
(integer) 1
127.0.0.1:6379> zrange salary 2 3
1) "8000"
127.0.0.1:6379> zrange salary 0 -1           产看所有正序
1) "5000"
2) "6000"
3) "8000"
127.0.0.1:6379> zrangebyscore salary -inf +inf      由小到大进行排序
1) "5000"
2) "6000"
3) "8000"

127.0.0.1:6379> zrevrange salary 0 -1    逆序查看所有
1) "8000"
2) "6000"
3) "5000"
127.0.0.1:6379> zcard salary             查看个数
(integer) 3
127.0.0.1:6379> zcount salary 300 2000       根据标志排序 查看所有的个数
(integer) 0
127.0.0.1:6379> zcount salary 2 3
(integer) 2
127.0.0.1:6379> 

127.0.0.1:6379> zrem salary 8000
(integer) 1

127.0.0.1:6379> zadd salary 2 9000       添加如果原来有会覆盖
(integer) 1
127.0.0.1:6379> zrange salary 0 -1      正序排序输出
1) "5000"
2) "6000"
3) "9000"
127.0.0.1:6379> 


127.0.0.1:6379> zrem salary 2   不能根据标志位进行删除 只能根据标志位进行默认排序
(integer) 0
127.0.0.1:6379> zrem salary 9000    要删除实际的元素
(integer) 1
127.0.0.1:6379> 


特殊类型

geo

geo底层是zset可以操作

127.0.0.1:6379> geoadd test1 23 23 nanning
(integer) 1
127.0.0.1:6379> type test1
zset
127.0.0.1:6379> 

地理位置 geospatial

geoadd添加地理位置

geopos 获取

geodist返回两个位置的距离(参数 km)

127.0.0.1:6379> geoadd test1 34.545 23.2332 beijing   添加
(integer) 1
127.0.0.1:6379> geoadd test1 23.34 23.66 nanjing
(integer) 1
127.0.0.1:6379> geoadd test1 45.65 66.55 xian
(integer) 1
127.0.0.1:6379> geopos test1 xian        获取
1) 1) "45.64999848604202271"
   2) "66.55000006237398225"

127.0.0.1:6379> geopos test1 nanjing km
1) 1) "23.34000080823898315"
   2) "23.6600010682477162"

127.0.0.1:6379> geodist test1 nanjing beijing km    两个元素间的距离
"1144.0777"

127.0.0.1:6379> zrange test1 0 -1        利用zset查看所有的元素
1) "nanjing"
2) "beijing"
3) "xian"


127.0.0.1:6379> geodist test1 xian beijing m       返回两个元素间的距离
"4881239.6414"
127.0.0.1:6379> geodist test1 xian beijing km
"4881.2396"

georadius以给定的经纬度为中心 找出某一半径内的元素(这个方法的测试有些处理的难度难测)

127.0.0.1:6379> georadius china:city 10 10 1212 km
1) "beijing"
2) "changcheng"
127.0.0.1:6379> 

georadiusbymember根据成员名称找附近

127.0.0.1:6379> georadiusbymember china:city beijing 1000 km
1) "beijing"
2) "changcheng"
127.0.0.1:6379> 

geohash距离的hash表示的字符串二维经纬度转为一维字符串

127.0.0.1:6379> geohash china:city beijing
1) "s1z0gs3y0z0"
127.0.0.1:6379> 

用zset的方法操作geo元素啊、

127.0.0.1:6379> zrange test 0 -1
1) "jiaotong"
2) "nanjing"
127.0.0.1:6379> zrem test nanjing
(integer) 1
127.0.0.1:6379> zrange test 0 -1
1) "jiaotong"
127.0.0.1:6379> 

Hyperloglog

统计不重复的数量 不存储实际的值

有0.81%的误差 ,但是我们们可以忽略

Redis HyperLogLog 是用来做基数统计的算法,HyperLogLog 的优点是,在输入元素的数量或者体积非常非常大时,计算基数所需的空间总是固定 的、并且是很小的。

在 Redis 里面,每个 HyperLogLog 键只需要花费 12 KB 内存,就可以计算接近 2^64 个不同元素的基 数。这和计算基数时,元素越多耗费内存就越多的集合形成鲜明对比。

但是,因为 HyperLogLog 只会根据输入元素来计算基数,而不会储存输入元素本身,所以 HyperLogLog 不能像集合那样,返回输入的各个元素
127.0.0.1:6379> pfadd try1 1 1 2 2 3 3
(integer) 1
127.0.0.1:6379> pfcount try1
(integer) 3
127.0.0.1:6379> pfadd try2 1 2 3 4 
(integer) 1
127.0.0.1:6379> pfcount try2
(integer) 4
127.0.0.1:6379> pfmerge try1 try2
OK
127.0.0.1:6379> pfcount try1
(integer) 4
127.0.0.1:6379> pfcount try2
(integer) 4
127.0.0.1:6379> pfadd try3 1 2
(integer) 1
127.0.0.1:6379> pfcount try3
(integer) 2
127.0.0.1:6379> pfadd try4 3 5
(integer) 1
127.0.0.1:6379> pfcount try4
(integer) 2
127.0.0.1:6379> pfmerge try3 try4
OK
127.0.0.1:6379> pfcount try3
(integer) 4
127.0.0.1:6379> pfcount try4
(integer) 2
127.0.0.1:6379> 

pfadd 添加元素到基数统计

pfcount 统计共有多少基数

pfmerge 合并两个基数统记

pfmerge try3 try4 默认合并到前一个 后面的 try4不变

bitmaps 位图

位存储

操作二进制数进行存储

setbit

getbit

bitcount 统计1的个数

例如用bitmaps记录周一到周日的打卡情况

一周打卡记录汇总
127.0.0.1:6379> setbit day 0 1
(integer) 0
127.0.0.1:6379> setbit day 1 0
(integer) 0
127.0.0.1:6379> setbit day 2 1
(integer) 0
127.0.0.1:6379> setbit day 3 0
(integer) 0
127.0.0.1:6379> setbit day 4 1
(integer) 0
127.0.0.1:6379> setbit day 5 0
(integer) 0
127.0.0.1:6379> setbit day 6 1
(integer) 0

查找出总共的打卡天数
127.0.0.1:6379> bitcount day
(integer) 4

127.0.0.1:6379> bitcount day 0 6
(integer) 4

查找某一天的打卡情况
127.0.0.1:6379> getbit day 4
(integer) 1
127.0.0.1:6379> getbit day 3
(integer) 0
127.0.0.1:6379> 

BITCOUNT统计指定位区间上值为1的个数
BITCOUNT key [start end]
从左向右从0开始,从右向左从-1开始,注意start和end是字节
BITCOUNT testkey 0 0 表示从索引0个字节到索引0个字节,就是第一个字节的统计
BITCOUNT testkey 0 -1 等同于BITCOUNT testkey
最常用的就是BITCOUNT testkey
一字节为8位

127.0.0.1:6379> setbit day 1 0
(integer) 0
127.0.0.1:6379> setbit day 2 0
(integer) 0
127.0.0.1:6379> setbit day 3 1
(integer) 0
127.0.0.1:6379> bitcount day
(integer) 1
127.0.0.1:6379> bitcount day 0 -1
(integer) 1
127.0.0.1:6379> bitcount day 0 2
(integer) 1

三 事务

重点:redis单条命令是保证原子性的,但是redis的事务是不保证原子性的

redis 事务的本质:一组命令的集合(放在了一个执行队列中),一个事务中的所有命令会被序列化,在事务的执行过程中,会按照顺序执行

一次性 顺序性 排他性

redis 的事务没有隔离级别的概念

所有的命令在事务中没有直接的被执行,只有发起执行命令的时候才会执行 Exec

redis的事务

(1)开启事务 multi

(2)命令入队 正常命令编写自动入队

(3)执行事务 exec (discard放弃事务 全部不执行)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> set key1 "v1"
QUEUED
127.0.0.1:6379> set key2 "v2"
QUEUED
127.0.0.1:6379> get key1
QUEUED
127.0.0.1:6379> get key2
QUEUED
127.0.0.1:6379> exec
1) OK
2) OK
3) "v1"
4) "v2"
127.0.0.1:6379> 

异常:

编译型异常(命令编写有错误 ,会直接提示 所有的命令都不执行 入队就显示错误了)

127.0.0.1:6379> multi
OK
127.0.0.1:6379> get key1
QUEUED

127.0.0.1:6379> setget key  错误命令 直接报错  编译异常 无法入队
(error) ERR unknown command `setget`, with args beginning with: `key`, 

127.0.0.1:6379> set key 1
QUEUED
127.0.0.1:6379> get key
QUEUED

127.0.0.1:6379> exec       编译时异常全部无法执行
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> 

运行时异常

命令编写的时候不报错,但是运行时产生异常,语法没错,入队不显示错误,仅仅是错误的命令不执行,一个事务中的其他命令仍然可以正常执行【redis的事务不保证原子性的】

但是MySQL中是坚决不可能的!!!

127.0.0.1:6379> multi        开启事务
OK
127.0.0.1:6379> set key v1        设值
QUEUED
127.0.0.1:6379> get key         取值
QUEUED
127.0.0.1:6379> get key2
QUEUED

127.0.0.1:6379> incr key    对字符串增值 (错误)
QUEUED                       运行时异常正常入队 编译不检查出来错误
                             
127.0.0.1:6379> set key3 4
QUEUED
127.0.0.1:6379> incr key3
QUEUED
127.0.0.1:6379> exec
1) OK
2) "v1"
3) "v2"
4) (error) ERR value is not an integer or out of range
5) OK
6) (integer) 5
127.0.0.1:6379> 

可以看到错误的命令 不执行,其他的命令正常执行  redis事务不保证原子性
乐观锁,悲观锁

watch就可实现乐观锁 监视 加锁 乐观锁 ( 相当于数据库添加 version相当于自旋锁)

unwatch 解锁

模拟多线程修改值(在事务前先获取锁,如果执行失败,就先解锁,重新加锁),举例子:

事务一:

127.0.0.1:6379> get money
"50"

127.0.0.1:6379> watch money      先获得锁
OK
127.0.0.1:6379> multi          开启事务
OK
127.0.0.1:6379> incrby money 20
QUEUED

------------------事务一先获得了监视锁,事务一没有执行的时候,事务二也获得了监视锁,进行了同一变量money值改变的操作
127.0.0.1:6379> decrby money 20
QUEUED

127.0.0.1:6379> exec              执行失败
(nil)  
------------------所以当事务二执行完后,相当于事务一之前获取的锁已经失效了,事务执行失败-----解决方法先unwatch 释放锁,重新加上监视锁重新的执行


解决:

127.0.0.1:6379> unwatch  先释放监视锁
OK
127.0.0.1:6379> watch money    重新的监视
OK
127.0.0.1:6379> get money
"30"
127.0.0.1:6379> multi      
OK
127.0.0.1:6379> incrby money 10
QUEUED
127.0.0.1:6379> exec        执行
1) (integer) 40
127.0.0.1:6379> unwatch      释放
OK
127.0.0.1:6379> 

事务二:

127.0.0.1:6379> get money
"50"
127.0.0.1:6379> watch money
OK
127.0.0.1:6379> decrby money 20
(integer) 30
127.0.0.1:6379> 



这篇关于redis学习的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程