基本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>
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
(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>