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> 

热门文章

暂无图片
编程学习 ·

C语言二分查找详解

二分查找是一种知名度很高的查找算法&#xff0c;在对有序数列进行查找时效率远高于传统的顺序查找。 下面这张动图对比了二者的效率差距。 二分查找的基本思想就是通过把目标数和当前数列的中间数进行比较&#xff0c;从而确定目标数是在中间数的左边还是右边&#xff0c;将查…
暂无图片
编程学习 ·

GMX 命令分类列表

建模和计算操作命令&#xff1a; 1.1 . 创建拓扑与坐标文件 gmx editconf - 编辑模拟盒子以及写入子组(subgroups) gmx protonate - 结构质子化 gmx x2top - 根据坐标生成原始拓扑文件 gmx solvate - 体系溶剂化 gmx insert-molecules - 将分子插入已有空位 gmx genconf - 增加…
暂无图片
编程学习 ·

一文高效回顾研究生课程《数值分析》重点

数值分析这门课的本质就是用离散的已知点去估计整体&#xff0c;就是由黑盒子产生的结果去估计这个黑盒子。在数学里这个黑盒子就是一个函数嘛&#xff0c;这门课会介绍许多方法去利用离散点最大化地逼近这个函数&#xff0c;甚至它的导数、积分&#xff0c;甚至微分方程的解。…
暂无图片
编程学习 ·

在职阿里5年,一个28岁女软测工程师的心声

简单的先说一下&#xff0c;坐标杭州&#xff0c;14届本科毕业&#xff0c;算上年前在阿里巴巴的面试&#xff0c;一共有面试了有6家公司&#xff08;因为不想请假&#xff0c;因此只是每个晚上去其他公司面试&#xff0c;所以面试的公司比较少&#xff09; ​ 编辑切换为居中…
暂无图片
编程学习 ·

字符串左旋c语言

目录 题目&#xff1a; 解题思路&#xff1a; 第一步&#xff1a; 第二步&#xff1a; 第三步&#xff1a; 总代码&#xff1a; 题目&#xff1a; 实现一个函数&#xff0c;可以左旋字符串中的k个字符。 例如&#xff1a; ABCD左旋一个字符得到BCDA ABCD左旋两个字符…
暂无图片
编程学习 ·

设计模式--观察者模式笔记

模式的定义与特点 观察者&#xff08;Observer&#xff09;模式的定义&#xff1a;指多个对象间存在一对多的依赖关系&#xff0c;当一个对象的状态发生改变时&#xff0c;所有依赖于它的对象都得到通知并被自动更新。这种模式有时又称作发布-订阅模式、模型-视图模式&#xf…
暂无图片
编程学习 ·

睡觉突然身体动不了,什么是睡眠痽痪症

很多朋友可能有这样的体验&#xff0c;睡觉过程中突然意识清醒&#xff0c;身体却动弹不了。这时候感觉非常恐怖&#xff0c;希望旁边有一个人推自己一下。阳光以前也经常会碰到这样的情况&#xff0c;一年有一百多次&#xff0c;那时候很害怕晚上到来&#xff0c;睡觉了就会出…
暂无图片
编程学习 ·

深入理解C++智能指针——浅析MSVC源码

文章目录unique_ptrshared_ptr 与 weak_ptrstd::bad_weak_ptr 异常std::enable_shared_from_thisunique_ptr unique_ptr 是一个只移型别&#xff08;move-only type&#xff0c;只移型别还有std::mutex等&#xff09;。 结合一下工厂模式&#xff0c;看看其基本用法&#xff…
暂无图片
编程学习 ·

@TableField(exist = false)

TableField(exist false) //申明此字段不在数据库存在&#xff0c;但代码中需要用到它&#xff0c;通知Mybatis-plus在做写库操作是忽略它。,.
暂无图片
编程学习 ·

Java Web day15

第十二章文件上传和下载 一、如何实现文件上传 要实现Web开发中的文件上传功能&#xff0c;通常需要完成两步操作&#xff1a;一.是在Web页面中添加上传输入项&#xff1b;二是在Servlet中读取上传文件的数据&#xff0c;并保存到本地硬盘中。 需要使用一个Apache组织提供一个…
暂无图片
编程学习 ·

【51nod 2478】【单调栈】【前缀和】小b接水

小b接水题目解题思路Code51nod 2478 小b接水 题目 输入样例 12 0 1 0 2 1 0 1 3 2 1 2 1输出样例 6解题思路 可以发现最后能拦住水的都是向两边递减高度&#xff08;&#xff1f;&#xff09; 不管两个高积木之间的的积木是怎样乱七八糟的高度&#xff0c;最后能用来装水的…
暂无图片
编程学习 ·

花了大半天写了一个UVC扩展单元调试工具

基于DIRECTSHOW 实现的&#xff0c;用的是MFC VS2019. 详见&#xff1a;http://www.usbzh.com/article/detail-761.html 获取方法 加QQ群:952873936&#xff0c;然后在群文件\USB调试工具&测试软件\UVCXU-V1.0(UVC扩展单元调试工具-USB中文网官方版).exe USB中文网 USB中文…
暂无图片
编程学习 ·

贪心(一):区间问题、Huffman树

区间问题 例题一&#xff1a;区间选点 给定 N 个闭区间 [ai,bi]请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。 输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数 N&#xff0c;表示区间数。 接下来 …
暂无图片
编程学习 ·

C语言练习实例——费氏数列

目录 题目 解法 输出结果 题目 Fibonacci为1200年代的欧洲数学家&#xff0c;在他的着作中曾经提到&#xff1a;「若有一只免子每个月生一只小免子&#xff0c;一个月后小免子也开始生产。起初只有一只免子&#xff0c;一个月后就有两只免子&#xff0c;二个月后有三只免子…
暂无图片
编程学习 ·

Android开发(2): Android 资源

个人笔记整理 Android 资源 Android中的资源&#xff0c;一般分为两类&#xff1a; 系统内置资源&#xff1a;Android SDK中所提供的已经定义好的资源&#xff0c;用户可以直接拿来使用。 用户自定义资源&#xff1a;用户自己定义或引入的&#xff0c;只适用于当前应用的资源…
暂无图片
编程学习 ·

零基础如何在短时间内拿到算法offer

​算法工程师是利用算法处理事物的职业 算法&#xff08;Algorithm&#xff09;是一系列解决问题的清晰指令&#xff0c;也就是说&#xff0c;能够对一定规范的输入&#xff0c;在有限时间内获得所要求的输出。 如果一个算法有缺陷&#xff0c;或不适合于某个问题&#xff0c;执…
暂无图片
编程学习 ·

人工智能:知识图谱实战总结

人工智能python&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习人工智能&#xff1a;知识图谱实战前言一、实体建模工具Protegepython&#xff0c;NLP&#xff0c;知识图谱&#xff0c;机器学习&#xff0c;深度学习 人工智能&#xff1a;知识图…
暂无图片
编程学习 ·

【无标题】

这里写自定义目录标题欢迎使用Markdown编辑器新的改变功能快捷键合理的创建标题&#xff0c;有助于目录的生成如何改变文本的样式插入链接与图片如何插入一段漂亮的代码片生成一个适合你的列表创建一个表格设定内容居中、居左、居右SmartyPants创建一个自定义列表如何创建一个注…