Redis基础知识一遍过!

136 阅读16分钟

「这是我参与11月更文挑战的第3天,活动详情查看:2021最后一次更文挑战

1、什么是NoSql

NoSql

NoSql=Not Only Sql(不仅仅是SQL)

关系型数据库∶表格,行,列

泛指非关系型数据库的,随着web2.0互联网的诞生!传统的关系型数据库很难对付web2.0时代!尤其是超大规模的高并发的社区!暴露出来很多难以克服的问题,NoSQL在当今大数据环境下发展的十分迅速,Redis是发展最快的,而且是我们当下必须要掌握的一个技术!

很多的数据类型用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式!

不需要多月的操作就可以横向扩展的! Map<String,Object>使用键值对来控制 !

NoSql特点:

解耦

1、方便扩展

2、大数据量高性能(Redi一秒写八万次,读取11万,NoSQl的缓存记录级,是一种细粒度的缓存,性能会比较高!)

3、数据类型是多样型的(不需要事先设计数据库!随取随用!如果是数据量十分大的表,很多人都无法设计了)

4、传统RDBMS和NoSql

传统的 RDBMS

  • 结构化组织

  • sQL

  • 数据和关系都存在单独的表中-操作操作,数据定义语言-严格的一致性

  • 基础的事务

Nosql

  • 不仅仅是数据

  • 没有固定的查询语言

  • 键值对存储,列存储,文档存储,图形数据库(社交关系)-最终一致性,

  • CAP定理和BASE(异地多活)初级架构师!(狂神理念:只要学不死,就往死里学!)

  • 高性能,高可用,高可扩

了解3v和3高

大数据时代的3v:主要是描述问题的

1、海量Volume

2、多样Variety

3、实时velocity

大数据时代的3高:主要是对程序的要求

1、高并发

2、高可扩

3、高性能

image-20210813093027725

image-20210813093311523

NoSQL四大分类:

KV键值对:

  • 新浪:Redis
  • 美团:Redis + Tair
  • 阿里、百度:Redis + memecache

文档型数据库( bson格式和json一样)∶

MongoDB(一般必须要掌握) o MongoDB是一个基于分布式文件存储的数据库,C++编写,主要用来处理大量的文档! o MongoDB是一个介于关系型数据库和非关系型数据中中间的产品!MongoDB是非关系型数据库中功能最丰富,最像关系型数据库的!

ConthDB

列存储数据库

  • Hbase
  • 分布式文件系统
要重点学习的数据库

Redis

MongoDb

HBase

Neo4j

Redis入门

概述

Redis是什么

Redis是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作==数据库==、==缓存==和==消息中间件MQ==。它支持

多种类型的数据结构,如字符串( strings ),散列 ( hashes ),列表( lists ),集合( sets ),有序集合( sorted sets )

与范围查询,bitmaps,hyperloglogs和地理空间 ( geospatial)索引半径查询。Redis 内置了复制( replication ),LUA脚本( Luascripting ),LRU驱动事件( LRU eviction),事务(transactions)和不同级别的磁盘持久化

(persistence ),并通过Redis哨兵 ( Sentinel )和自动分区( Cluster)提供高可用性( high availability )。

Redis ( Remote Dictionary Server ),即远程字典服务!

是一个开源的使用ANSl C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种

语言的API.redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件,并且在此基础上实现了

master-slave(主从)同步免费和开源!是当下最热门的NoSQL技术之一!也被人们称之为结构化数据库!

Redis能干什么?

1、内存存储、持久化,内存中是断电即失、所以说持久化很重要(rdb、aof)

2、效率高,可以用于高速缓存

3、发布订阅系统

4、地图信息分析

5、计时器、计数器(浏览量!)

特性

1、多样化的数据类型

2、持久化

3、集群

4、事务

image-20210813113033212

Redis常用命令

查看当前数据库的所以key keys *

清除当前数据库 flushdb

清楚全部数据库的内容 FLUSHALL

切换数据库select 3

查看DB大小 DBSIZE

设置过期秒数EXPIRE key 10

查看key剩余时间ttl name

移动当前的key到指定的数据库 move name 1

查看当前key的类型type name

判断key是否存在EXISTS key

向key中的value值追加内容,==如果当前key不存在就相当于set key value==APPEND key "hello"

image-20210813150932697

Redis为什么使用单线程还那么快

1、误区1∶高性能的服务器一定是多线程的?

2、误区2∶多线程(CPU上下文会切换!)一定比单线程效率高!

先去CPU>内存>硬盘的速度要有所了解!

核心: redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率就是最高的,多线程(CPU上下文会

切换︰耗时的操作!!!),对于内存系统来说,如果没有上下文切换效率就是最高的!多次读写都是在一个CPU上的

在内存情况下,这个就是最佳的方案!

五大数据类型

Redis-Key

设置过期秒数`EXPIRE key 10`

查看key剩余时间`ttl name`

移动当前的key到指定的数据库 `move name 1`

查看当前key的类型`type name`

判断key是否存在`EXISTS key`

向key中的value值追加内容,==如果当前key不存在就相当于set key value==`APPEND key "hello"`

String(字符串


127.0.0.1:6379> set view 0
OK
127.0.0.1:6379> incr view #增加1
(integer) 1
127.0.0.1:6379> incr view
(integer) 2
127.0.0.1:6379> decr view #减少1
(integer) 1
127.0.0.1:6379> INCRBY  view 10 #增加指定的数量
(integer) 11
127.0.0.1:6379> DECRBY view 5  #减少指定的数量
(integer) 6
127.0.0.1:6379> DECRBY VIEW 1
(integer) -1


######################################################
##字符串范围

127.0.0.1:6379> set name "today is nice"
OK
127.0.0.1:6379> get name
"today is nice"
127.0.0.1:6379> getrange name 5 10 ##获取指定长度的字符串
" is ni"
127.0.0.1:6379> 

######################################################
##替换字符串
127.0.0.1:6379> setrange name 8 "a happyday"  ##替换指定位置开始的字符串
(integer) 18
127.0.0.1:6379> get name
"today isa happyday"
127.0.0.1:6379> 

######################################################
# setex(set with expire) ##设置过期时间
# setnx(set if not exist) ##不存在则设置(在分布式锁中常常用到)

######################################################
#mset 一次性创建多个key-value
#mget 一次性得到多个key值
127.0.0.1:6379> mset k1 v1 k2 v2 
OK
127.0.0.1:6379> mget k1 k2
1) "v1"
2) "v2"


######################################################
#msetnx 是一个原子性的操作,要么一起成功,要么一起失败!

127.0.0.1:6379> msetnx k3 v1 k2 v2
(integer) 0
127.0.0.1:6379> get k3
(nil)
127.0.0.1:6379> 

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

#这里的key是一个巧妙的设计:user:{id}:{filed},如此设计在redis中完全是ok了
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 20
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "20"

######################################################
#getset 先get 再set,并设置新的值(常用来做更新)

27.0.0.1:6379> getset db redis
(nil)
127.0.0.1:6379> get db
"redis"
127.0.0.1:6379> getset db monodb
"redis"
127.0.0.1:6379> get db
"monodb"
127.0.0.1:6379> 

String类似的使用场景

value除了是我们的字符串还可以是我们的数字!

  • 计数器
  • 统计多单位的数量
  • 粉丝数
  • 对象缓存存储!

List(列表)

所有的list命令以 l 开头

==list中的值有序且可重复==

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

127.0.0.1:6379> LPUSH list one  ##将一个值或者多个值,插入到列表尾部(左)
(integer) 1
127.0.0.1:6379> LPUSH list two
(integer) 2
127.0.0.1:6379> LPUSH list three
(integer) 3
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> Rpush list f 
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1 从右往左插入到列表头部
1) "three"
2) "two"
3) "one"
4) "f"
############################################################
Rpop #从右往左移除
Lpop #从左往右移除 可以指定长度

127.0.0.1:6379> Rpop list 
"f"
127.0.0.1:6379> Lpop list 2
1) "three"
2) "two"
127.0.0.1:6379> LRANGe list 0 -1
1) "one"

############################################################
127.0.0.1:6379> lrange list 0 -1
1) "six"
2) "two"
3) "one"
127.0.0.1:6379> lindex list 0 #从头开始取下标
"six"
127.0.0.1:6379> lindex list 1
"two"
127.0.0.1:6379> lindex list 2
"one"
############################################################

127.0.0.1:6379> llen list #取列表长度
(integer) 3

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

127.0.0.1:6379> lrange list 0 -1
1) "six"
2) "two"
3) "one"
127.0.0.1:6379> lrem list 1 six  #移除list中指定长度的value值
(integer) 1
127.0.0.1:6379> lrem list 1 six
(integer) 0
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"


############################################################
#Redis Ltrim 对一个列表进行修剪(trim),就是说,让列表只保留指定区间内的元素,不在指定区间之内的元素都将被删除。

127.0.0.1:6379> rpush list one
(integer) 1
127.0.0.1:6379> rpush list two
(integer) 2
127.0.0.1:6379> rpush list three
(integer) 3
127.0.0.1:6379> rpush list fourth
(integer) 4
127.0.0.1:6379> ltrim list  2 3
OK
127.0.0.1:6379> lrange 0 -1
(error) ERR wrong number of arguments for 'lrange' command
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "fourth"

############################################################
lset #更换已经存在的list中的指定下标的元素,列表不存在会报错
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "fourth"
127.0.0.1:6379> lset list 0 one
OK
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "fourth"
127.0.0.1:6379> 

############################################################
127.0.0.1:6379> exists list #判断列表是否存在
(integer) 1

############################################################
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "fourth"
127.0.0.1:6379> exists list
(integer) 1
127.0.0.1:6379> linsert list before fourth three #插入元素,可指定轴点
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "three"
3) "fourth"
127.0.0.1:6379> 


image-20210813195759253

image-20210813192441519

小结

  • 他实际上是一个链表,before Node after,left,right都可以插入值
  • 如果key不存在,创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在!
  • 在两边插入或者改动值,效率最高!中间元素,相对来说效率都会低一点~

消息排队!消息队列(Lpush Rpop) ,栈(Lpush Lpop)

Set(集合)

==set中的值无序,不可重复==

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

127.0.0.1:6379> sadd myset one #存值
(integer) 1
127.0.0.1:6379> sadd myset two
(integer) 1
127.0.0.1:6379> smembers myset #取值
1) "two"
2) "one"
127.0.0.1:6379> sismember myset two #查看指定元素是否存在
(integer) 1
127.0.0.1:6379> 

########################################################
#获取set集合中的内容元素的个数
127.0.0.1:6379> scard myset
(integer) 2

########################################################
#删除srt集合中的指定元素
127.0.0.1:6379> smembers myset
1) "two"
2) "ff"
3) "f"
4) "one"
127.0.0.1:6379> srem myset ff
(integer) 1
127.0.0.1:6379> smembers myset
1) "two"
2) "f"
3) "one"

########################################################
#随机set集合中的元素(可以指定长度)
127.0.0.1:6379> srandmember myset
"two"
127.0.0.1:6379> srandmember myset
"one"
127.0.0.1:6379> srandmember myset
"two"
127.0.0.1:6379> srandmember myset
"one"

########################################################
#随即删除set集合中的元素
127.0.0.1:6379> spop myset
"one"
127.0.0.1:6379> spop myset
"two"
127.0.0.1:6379> spop myset
"f"

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

127.0.0.1:6379> sadd myset1 one
(integer) 1
127.0.0.1:6379> sadd myset1 two
(integer) 1
127.0.0.1:6379> sadd myset1 three
(integer) 1
127.0.0.1:6379> sadd myset2  fourth
(integer) 1
127.0.0.1:6379> smove myset1 myset2 three  #将一个指定的值,移动到宁外一个set集合中
(integer) 1
127.0.0.1:6379> smembers myset1
1) "two"
2) "one"
127.0.0.1:6379> smembers myset2
1) "three"
2) "fourth"

########################################################
127.0.0.1:6379> sadd key1 a
(integer) 1
127.0.0.1:6379> sadd key1 b
(integer) 1
127.0.0.1:6379> sadd key1 c
(integer) 1
127.0.0.1:6379> sadd key2 c
(integer) 1
127.0.0.1:6379> sadd key2 d
(integer) 1
127.0.0.1:6379> sadd key2 e
(integer) 1
127.0.0.1:6379> sdiff key1 key2 #差集
1) "a"
2) "b"
127.0.0.1:6379> sinter key1 key2 #交集  (共同关注)
1) "c"
127.0.0.1:6379> sunion key1 key2 #并集
1) "e"
2) "b"
3) "c"
4) "d"
5) "a"

image-20210813204952840

Hash(哈希)

Map集合,key-map! 时候这个值是一个map集合!本质和string类型没有太大区别,还是一个简单的key-value!

127.0.0.1:6379> hset key1 field hello
(integer) 1
127.0.0.1:6379> hget key1
(error) ERR wrong number of arguments for 'hget' command
127.0.0.1:6379> hget key1 field
"hello"
127.0.0.1:6379> hmset key2 field one field two field three
OK
127.0.0.1:6379> hget key2 field
"three"
127.0.0.1:6379> hmget key2 field
1) "three"
127.0.0.1:6379> hgetall key2
1) "field"

#########################################################
127.0.0.1:6379> hset key2 fie one
(integer) 1
127.0.0.1:6379> hgetall key2
1) "field"
2) "three"
3) "fie"
4) "one"
127.0.0.1:6379> hdel key2 fie #删除hash指定的key,对应的value值也就没有了
(integer) 1
127.0.0.1:6379> hgetall key2
1) "field"
2) "three"

###########################################################
#获取hash长度
127.0.0.1:6379> hgetall key2
1) "field"
2) "three"
127.0.0.1:6379> hlen key2
(integer) 1

############################################################
127.0.0.1:6379> hget key1 field
"two"
127.0.0.1:6379> hexists key1 field #判断哈希中的值是否存在
(integer) 1
127.0.0.1:6379> hexists key1 field1
(integer) 0

############################################################
127.0.0.1:6379> hmset key2 f1 one f2 two
OK
127.0.0.1:6379> hkeys key2 #查看所有的key
1) "f1"
2) "f2"
127.0.0.1:6379> hvals key2 #查看所有的value
1) "one"
2) "two"

############################################################
incr decr
127.0.0.1:6379> hset myhash fie1d3 5#指定增量!
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 1
(integer) 6
127.0.0.1:6379> HINCRBY myhash fie1d3 -1
(integer) 5
127.0.0.1:6379> hsetnx myhash field4 hel1o#如果不存在则可以设置
(integer) 1
127.0.0.1:6379> hsetnx myhash fie1d4 wor1d# 如果存在则不能设置
(integer) o


image-20210814093107737

Zset(有序集合)

####################################################################
127.0.0.1:6379> zadd myset 1 one  #放入一个值
(integer) 1
127.0.0.1:6379> zadd myset 2 two 3 three  #放入多个值
(integer) 2
127.0.0.1:6379> zrange myset 0 -1 #遍历
1) "one"
2) "two"
3) "three"

####################################################################
127.0.0.1:6379> zadd salary 1000 zahngasn 500 lisi 800 wangwu
(integer) 3
127.0.0.1:6379> zrangebyscore salary -inf +inf #按某项值从小到大排序
1) "lisi"
2) "wangwu"
3) "zahngasn"
127.0.0.1:6379> zrevrange salary 0 -1 #从大到小排序
1) "zahngasn"
2) "wangwu"
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #按某项值从小到大排序,显示vlaue
1) "lisi"
2) "500"
3) "wangwu"
4) "800"
5) "zahngasn"
6) "1000"
127.0.0.1:6379> zrange salary 0 -1  #从小到大排序(遍历)
1) "lisi"
2) "wangwu"
3) "zahngasn"

####################################################################
127.0.0.1:6379> zrem salary lisi #删除某项值
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "wangwu"
2) "zahngasn"
127.0.0.1:6379> zcard salary #获取集合中的个数
(integer) 2

####################################################################
127.0.0.1:6379> zadd myset 1 hello
(integer) 1
127.0.0.1:6379> zadd myset 2 wor1d 3 kuangshen
(integer) 2
127.0.0.1:6379> zcount myset 1 3 #获取推定区间的成员数量! 
(integer) 3
127.0.0.1:6379> zcount myset 1 2(integer) 2

其与的一些APl,通过我们的学习吗,你们剩下的如果工作中有需要,这个时候你可以去查查看官方文档!案例思路: set排序存储班级成绩表,工资表排序! 普通消息,1,重要消息2,带权重进行判断! 排行榜应用实现,取Top N测试!

三种特殊数据类型

geospatial 地理位置

##########################################################################
#geoadd 添加地理位置
#规则:两级无法直接添加,一般下载城市数据,通过java程序一次性导入
#有效的经度从-180度到180度。
#有效的纬度从-85.05112878度到85.05112878度。

127.0.0.1:6379> geoadd nanchang 115.89 28.67 qingsahnhu 226.89 28.68 hongutan
(error) ERR invalid longitude,latitude pair 226.890000,28.680000
127.0.0.1:6379> geoadd nanchang 115.89 28.67 qingsahnhu 
(integer) 1
127.0.0.1:6379> geoadd nanchang 115.87 28.65 hongutan 
(integer) 1
127.0.0.1:6379> geoadd nanchang 115.96 28.68 wanli
(integer) 1
127.0.0.1:6379> geoadd nanchang 115.54 28.84 anyi
(integer) 1

########################################################################
 #获取指定城市的经纬度
127.0.0.1:6379> geopos nanchang anyi
1) 1) "115.54000228643417358"
   2) "28.84000031973250344"
127.0.0.1:6379> geopos nanchang qingsahnhu
1) 1) "115.88999837636947632"
   2) "28.66999910629679249"




geodist

指定单位的参数 unit 必须是以下单位的其中一个:

  • m 表示单位为米。
  • km 表示单位为千米。
  • mi 表示单位为英里。
  • ft 表示单位为英尺。
#查询两地的直线距离
127.0.0.1:6379> geodist nanchang wanli anyi
"44651.6392"
127.0.0.1:6379> geodist nanchang wanli anyi km
"44.6516"

georanius 以给定的经纬度为中心, 找出某一半径内的元素

127.0.0.1:6379> georadius nanchang 120 30 1000 km
1) "anyi"
2) "hongutan"
3) "qingsahnhu"
4) "wanli"


127.0.0.1:6379> georadius nanchang 120 30 1000 km withdist #显示到中间距离的位置
1) 1) "anyi"
   2) "450.9097"
2) 1) "hongutan"
   2) "427.6863"
3) 1) "qingsahnhu"
   2) "425.0559"
4) 1) "wanli"
   2) "418.2912"
127.0.0.1:6379> georadius nanchang 120 30 1000 km withcoord # 显示他人的定位信息
1) 1) "anyi"
   2) 1) "115.54000228643417358"
      2) "28.84000031973250344"
2) 1) "hongutan"
   2) 1) "115.86999982595443726"
      2) "28.65000015634961272"
3) 1) "qingsahnhu"
   2) 1) "115.88999837636947632"
      2) "28.66999910629679249"
4) 1) "wanli"
   2) 1) "115.95999866724014282"
      2) "28.68000111599155133"
127.0.0.1:6379> georadius nanchang 120 30 1000 km withcoord count 1  #筛选出指定的结果
1) 1) "wanli"
   2) 1) "115.95999866724014282"
      2) "28.68000111599155133"

#找出位于指定元素周围的其他元素!
127.0.0.1:6379> GEORADIUSBYMEMBER china:city beijing 1000 km
1)"beijing"
2) "xian"
127.0.0.1:6379> GEORADIUSBYMEMBER china:city shanghai 400 km
1) "hangzhou"
2) "shanghai"

georadiusbymember

image-20210814110940959

geo底层的实现原理其实就是zset!我们可以使用zset命令来操作geo!

127.0.0.1:6379> zrange nanhcang 0 -1 #查看所有元素
(empty array)
127.0.0.1:6379> zrange nanchang 0 -1
1) "anyi"
2) "hongutan"
3) "qingsahnhu"
4) "wanli"
127.0.0.1:6379> zrem nanchang wanli #移除指定的元素
(integer) 1
127.0.0.1:6379> zrange nanchang 0 -1
1) "anyi"
2) "hongutan"
3) "qingsahnhu"

Hyperloglog

什么是基数:一个集合中不重复的元素

简介

Redis 2.8.9版本就更新了Hyperloglog数据结构!

Redis Hyperloglog 基数统计的算法!

优点∶占用的内存是固定,2^64不同的元素的技术,只需要废12KB内存!如果要从内存角度来比较的话 Hyperloglog首选!

网页的UV(一个人访问一个网站多次,但是还是算作一个人! )

传统的方式,set保存用户的id,然后就可以统计set 中的元素数量作为标准判断!

这个方式如果保存大量的用户id,就会比较麻烦!我们的目的是为了计数,

而不是保存用户id ;0.81%错误率!统计UV任务,可以忽略不计的!

语法

127.0.0.1:6379> pfadd key1 a b c d e f g 
(integer) 1
127.0.0.1:6379> pfcount key1 #统计不重复的元素(基数数量)
(integer) 7
127.0.0.1:6379> pfadd key2 a a i j k l o n h m n
(integer) 1
127.0.0.1:6379> pfcount key2
(integer) 9
127.0.0.1:6379> pfmerge key3 key1 key2 #合并两个集合
OK
127.0.0.1:6379> pfcount key3
(integer) 15

如果允许容错的话,那么一定可以使用Hyperloglog

如果不允许容错,就使用set或者自己的数据类型即可

Bitmap

位运算

统计用户信息,活跃,不活跃!登录、未登录! 打卡,365打卡!

两个状态的,都可以使用Bitmaps ! Bitmaps位图,数据结构!

都是操作二进制位来进行记录,就只有0和1两个状态!

365天= 365 bit 1字节=8bit 46个字节左右!

使用bitmap来记录周一到周日的打卡!

周一 :0 周二 :1 周三 :0 ...


127.0.0.1:6379> setbit key 0 1 #存值
(integer) 0
127.0.0.1:6379> setbit key 1 1
(integer) 0
127.0.0.1:6379> setbit key 2 0
(integer) 0
127.0.0.1:6379> setbit key 3 0
(integer) 0
127.0.0.1:6379> setbit key 4 1
(integer) 0
127.0.0.1:6379> setbit key 5 1
(integer) 0
127.0.0.1:6379> setbit key 6 0
(integer) 0
127.0.0.1:6379> setbit key 7 1
(integer) 0

#查看某一天是否打卡
127.0.0.1:6379> getbit key 3   #取值
(integer) 0
127.0.0.1:6379> getbit key 4
(integer) 1

#查看打卡的天数
127.0.0.1:6379> bitcount key
(integer) 5



事务

Redis事务本质:一组命令的集合!一个事务中的所有命令都会被序列化,在事务执行过程的中,会按照顺序执行!一次性、顺序性、排他性!

执行一些列的命令!

-----------队列 set set get set 执行-------------

mysql (ACID) :隔离性、持久性、原子性、一致性

==Redis十五没有个理解级别==

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

==REdis单条命令是保证原子性的,但是其事务是不保证原子性的==

127.0.0.1:6379> multi #开启事务,命令入队列
OK
127.0.0.1:6379(TX)> set name v1
QUEUED
127.0.0.1:6379(TX)> set name v2
QUEUED
127.0.0.1:6379(TX)> get name
QUEUED
127.0.0.1:6379(TX)> exec  #执行,队列命令出队执行
1) OK
2) OK
3) "v2"

放弃事务

127.0.0.1:6379> MULTI
OK
127.0.0.1:6379(TX)> set name one
QUEUED
127.0.0.1:6379(TX)> set name2 two
QUEUED
127.0.0.1:6379(TX)> set name3 three
QUEUED
127.0.0.1:6379(TX)> DISCARD
OK
127.0.0.1:6379> get name2
(nil)

编译时异常(代码有问题!命令有错!) 事务中所有的命令都不会被执行

127.0.0.1:6379> multi
oK
127.0.0.1:6379>set k1 v1
QUEUED
127.0.0.1:6379>set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> getset k3#错误的命令
(error) ERR wrong number of arguments for 'getset' command
127.0.0.1:6379> set k4 v4
QUEUED
127.0.0.1:6379> set k5 v5
QUEUED
127.0.0.1:6379> exec#执行事务报错!
(error) EXECABORT Transaction discarded because of previous errors.
127.0.0.1:6379> get k5#所有的命令都不会被执行!
(ni1)

运行时异常(1/0),如果事务队列中存在语法性,那么执行命令的时候,其他命令是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> set k1 "v1"
OK
127.0.0.1:6379> multi 
OK
127.0.0.1:6379> incr k1
QUEUED
127.0.0.1:6379>set k2 v2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> get k3
QUEUED
127.0.0.1:6379>exec
1)(error) ERR value is not an integer or out of range)2)OK
3) oK4) "v3"
127.0.0.1:6379> get k2
"v2"
127.0.0.1:6379>get k3
"v3"

监控!watch

悲观锁

  • 很悲观,认为什么时候都会出现问题,无论做什么都会加锁

乐观锁

  • 很乐观,认为什么时候都不会出现问题,所以不会加锁!跟新数据的时候去判断一下,在此期间是否有人修改过这个数据
  • 获取version
  • 更新的时候比较version

Redis监控测试

正常执行

127.0.0.1:6379> set money 100
OK
127.0.0.1:6379>set out o
oK
127.0.0.1:6379> watch money#监视money对象
OK
127.0.0.1:6379> multi#事务正常结束,数据期间没有发生变动,这个时候就正常执行成功!
OK
127.0.0.1:6379>DECRBY money 20
QUEUED
127.0.0.1:6379> INCRBY out 20
QUEUED
127.0.0.1:6379>exec
1) (integer) 80
2)(integer) 20

################################################
##测试多线程修改值,使用watch可以当做redis的乐观锁操作!
127.0.0.1:6379>watch money#监视money
OK
127.0.0.1:6379> multi 
oK
127.0.0.1:6379> DECRBY money 10
QUEUED
127.0.0.1:6379> INCRBY out 10
QUEUED
127.0.0.1:6379> exec#执行之前,另外一个线程,修改了我们的值,这个时候,就会导致事务执行失败!(ni1)

如果修改失败,获取最新的值就好

image-20210814143246301

Jedis

我们要使用Java来操作Redis,知其然并知其所以然,授人以渔!学习不能急躁,慢慢来会很快!

什么是Jedis是Redis官方推荐的java连接开发工具!使用lava 操作Red is 中间件!如果你要使用java操作redis,那么一定要对Jedis 十分的熟悉!

测试

  • 创建一个普通maven项目
<!--导入jedis依赖-->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>3.6.0</version>
        </dependency>
        <!--导入fastjson依赖-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.56</version>
        </dependency>
    </dependencies>
  • 编码测试