600字范文,内容丰富有趣,生活中的好帮手!
600字范文 > Redis五大数据类型及三大特殊类型的基本操作(入门)和Redis事务

Redis五大数据类型及三大特殊类型的基本操作(入门)和Redis事务

时间:2024-02-17 07:31:55

相关推荐

Redis五大数据类型及三大特殊类型的基本操作(入门)和Redis事务

Redis入门

说明:这篇文章是在学习b站狂神的Redis教程时,跟着做的笔记,里面可能有一些偷懒或者不全面之处,望指正,抱拳了🤘

概述

Redis是什么?

Redis(Remote Dictionary Server),即远程字典服务!是当下最热门的NoSQL技术之一,也被人们称为结构化数据库

Redis能干嘛?

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

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

3、发布订阅系统

4、地图信息分析

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

6、……

Redis的特性

1、多样的数据类型

2、持久化

3、集群

4、事务

学习中需要用到的东西

1、官网:https://redis.io/

2、Redis中文网:/

3、下载地址(托管在github上):官网下载

windows在github上下载,停更很久了(官方不建议在windows上开发Redis)/microsoftarchive/redis/releases/tag/win-3.2.100

Redis推荐都是在Linux服务器上搭建

Windows安装

1、下载压缩包

2、解压到自己的电脑上

3、开启服务,双击运行服务即可

4、使用Redis客户端来连接Redis

5、使用Redis

Windows下使用简单,但是Redis推荐使用Linux进行开发

测试性能

redis-benchmark是一个压力测试工具(官方自带)

redis-benchmark命令参数

简单测试:

测试:50个并发连接 每个并发10000个请求redis-benchmark -h localhost -p 6379 -c 50 -n 10000

参数解读:

100000 requests completed in 2.16 seconds

50 parallel clients

3 bytes payload

keep alive: 1

100000个请求,使用2.16秒

每次请求50个并发

每次只写入三个字符串

只有一台服务器来处理这些请求,单机性能

77.40% <= 1 milliseconds 第一毫秒处理77.40%

97.29% <= 2 milliseconds 第二毫秒处理97.29%

99.87% <= 3 milliseconds 第三毫秒处理99.87%

100.00% <= 3 milliseconds 所有请求在三毫秒处理完成

41476.57 requests per second 每秒处理41476.57次请求

Redis基础知识

redis默认有16个数据库(在redis.windows.conf中查看)

默认使用的是第0个数据,可以使用select进行切换数据库

Redis的基本命令

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

切换数据库

127.0.0.1:6379> select 3 #切换数据库OK127.0.0.1:6379[3]> dbsize #查看数据库大小(integer) 0127.0.0.1:6379[3]> set name maize3 #存入一个数据OK127.0.0.1:6379[3]> dbsize #数据库大小变为1(integer) 1

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

查看当前数据库的key

127.0.0.1:6379[3]> keys * #keys *命令查看当前数据库所有的key1) "name"

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

使用flushdb清空当前数据库

127.0.0.1:6379[3]> flushdb #清空当前数据库OK127.0.0.1:6379[3]> keys *(empty list or set)

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

使用flushall清空所有数据库

127.0.0.1:6379> select 0OK127.0.0.1:6379> keys *1) "key:__rand_int__"2) "counter:__rand_int__"3) "name"4) "mylist"127.0.0.1:6379> select 3OK127.0.0.1:6379[3]> flushall #清空所有数据库OK127.0.0.1:6379[3]> select 0OK127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379>

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

判断某个key是否存在,存在返回1,不存在返回0

127.0.0.1:6379> exists name(integer) 0127.0.0.1:6379> set name maizeOK127.0.0.1:6379> exists name(integer) 1

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

将某个key转移到指定数据库

127.0.0.1:6379> move name 1 #将当前数据库下的name移到数据库1中(integer) 1127.0.0.1:6379> keys *(empty list or set)127.0.0.1:6379> select 1OK127.0.0.1:6379[1]> keys *1) "name"127.0.0.1:6379[1]>

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

设置key值的过期时长,单位为秒

127.0.0.1:6379> set name maizeOK127.0.0.1:6379> expire name 20 #expire设置key的过期时长(integer) 1127.0.0.1:6379> ttl name #ttl来获取key的剩余时长(integer) 18127.0.0.1:6379> ttl name(integer) 12127.0.0.1:6379> ttl name(integer) 7127.0.0.1:6379> ttl name(integer) 3127.0.0.1:6379> ttl name #剩余时长为-2,说明已经过期(integer) -2127.0.0.1:6379> get name(nil)127.0.0.1:6379> setex key3 20 hello #在创建key时设置key的过期时长(20s后过期),单位为秒OK127.0.0.1:6379> ttl key3(integer) 16

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

移除指定key

127.0.0.1:6379> set name maizeOK127.0.0.1:6379> get name"maize"127.0.0.1:6379> del name(integer) 1127.0.0.1:6379> get name(nil)

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

查看指定key的类型(type)

127.0.0.1:6379> set name maizeOK127.0.0.1:6379> set age 0OK127.0.0.1:6379> keys *1) "age"2) "name"127.0.0.1:6379> type namestring127.0.0.1:6379> type agestring

更多的命令可以在官网查询

官方表示,Redis是基于内存操作的,CPU不是Redis的瓶颈,Redis的瓶颈时根据机器的内存和网络的带宽。

Redis为什么单线程还这么快?

redis是将所有的数据全部放在内存中,所以说使用单线程去操作效率就是最高的(多线程会有CPU的上字阿文切换行为,这是一个耗时的操作),对于内存系统来说,如果没有上下文切换,效率最高。

Redis String

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

在指定key后追加字符串(append)

当key不存在时,会创建一个key,并将字符串赋值给key

127.0.0.1:6379> get name"maize"127.0.0.1:6379> append name -j #在name后添加"-j"(integer) 7 #添加完成后的字符串长度127.0.0.1:6379> get name"maize-j"

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

实现i++和i–的操作

127.0.0.1:6379> set views 0OK127.0.0.1:6379> get views"0"127.0.0.1:6379> incr views #将views+1,即自增1(integer) 1127.0.0.1:6379> get views"1" #views从原来的0变为1127.0.0.1:6379> decr views #将views-1,自减1(integer) 0127.0.0.1:6379> get views"0" #views从原来的1变为0

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

设置增长步长(即i+n),和减少步长(i-n)

127.0.0.1:6379> incrby views 10 #views+10(integer) 10127.0.0.1:6379> get views"10"127.0.0.1:6379> decrby views 5 #views-5(integer) 5127.0.0.1:6379> get views"5"

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

截取字符串

127.0.0.1:6379> get name"maize-jhelloworld"127.0.0.1:6379> getrange name 2 5 #相当于java的subString方法,截取索引从2-5的字符串"ize-"127.0.0.1:6379> getrange name 0 -1 #范围为0到-1表示查看所有的字符串"maize-jhelloworld"127.0.0.1:6379> getrange name 2 -1 #范围为2到-1表示查看索引为2到字符串末尾的片段"ize-jhelloworld"

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

给字符串片段赋值

127.0.0.1:6379> set key2 abcdefghijklOK127.0.0.1:6379> get key2"abcdefghijkl"127.0.0.1:6379> setrange key2 1 xxx #从索引为1的字符开始替换,替换的长度和要替换的字符串长度相等(integer) 12127.0.0.1:6379> get key2"axxxefghijkl"127.0.0.1:6379>

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

key不存在时,才能设置,否则设置失败(返回值为0)

127.0.0.1:6379> setnx mykey hello(integer) 1127.0.0.1:6379> get mykey"hello"127.0.0.1:6379> setnx mykey world(integer) 0127.0.0.1:6379> get mykey"hello"

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

批量设置和批量获取值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3OK127.0.0.1:6379> keys *1) "views"2) "k3"3) "k2"4) "k1"5) "name"6) "age"7) "key2"8) "mykey"127.0.0.1:6379> mget k1 k2 k31) "v1"2) "v2"3) "v3"

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

批量添加数据原子性操作

127.0.0.1:6379> keys *1) "k2"2) "k1"3) "k3"127.0.0.1:6379> msetnx k1 v1 k4 v4 #有重复的key值,设置不会成功,原子性操作,因此k1和k4的值设置都不会成功(integer) 0127.0.0.1:6379> keys * #此处没有k4的值1) "k2"2) "k1"3) "k3"

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

对象的存储

127.0.0.1:6379> set user:2 {name:cyj,age:2} #设置一个user:2对象,值为json字符来保存一个对象OK127.0.0.1:6379> get user:2"{name:cyj,age:2}" #获取到的值也为json字符串# 这里的key是一个巧妙的设计,user:{id}:{filed},如此设计在Redis中是完全ok的127.0.0.1:6379> mset user:1:name maize user:1:age 0OK127.0.0.1:6379> mget user:1:name user:1:age1) "maize"2) "0"

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

获取值并设置值

#getset命令是先get再set,因此在首次设置时,获取到的值为空

#getset命令 非首次设置时(即存在值时),会先获取当前值,再对值进行修改

127.0.0.1:6379> getset name maize (nil)127.0.0.1:6379> get name"maize"127.0.0.1:6379> getset name cyj"maize"127.0.0.1:6379> get name"cyj"

Redis List

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

在Redis中,有关于list的操作是以l开头的,在push时是以l或r开头的,l表示从左边push,r表示从右边push (push时是可以存在重复值的)

127.0.0.1:6379> lpush list one #将一个值或多个值插入list的头部(integer) 1127.0.0.1:6379> lpush list two(integer) 2127.0.0.1:6379> lpush list three(integer) 3127.0.0.1:6379> lrange list 0 -1 #返回出来的值为存入时的逆序(先进后出->栈)1) "three"2) "two"3) "one"127.0.0.1:6379> lrange list 0 1 #通过区间获取具体的值1) "three"2) "two"127.0.0.1:6379> rpush list four #将一个值或多个值插入list的尾部,从右边push时,可以作为队列来对待(先进先出)(integer) 4127.0.0.1:6379> rpush list five(integer) 5127.0.0.1:6379> lrange list 0 -1 1) "three"2) "two"3) "one"4) "four"5) "five"

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

跟push对应的,移除一个元素也有左右之分,为lpop和rpop(移除列表中对应方向的第一个元素)

127.0.0.1:6379> lrange list 0 -11) "three"2) "two"3) "one"4) "four"5) "five"127.0.0.1:6379> lpop list #移除左边的第一个元素"three"127.0.0.1:6379> rpop list #移除右边的第一个元素"five"127.0.0.1:6379> lrange list 0 -11) "two"2) "one"3) "four"

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

根据下标获取某个元素的值,lindex

127.0.0.1:6379> lindex list 0"two"127.0.0.1:6379> lindex list 2"four"

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

lLen获得当前list的长度(存入多少个值)

127.0.0.1:6379> llen list(integer) 3

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

lrem,移除list中指定的值

127.0.0.1:6379> lpush list one(integer) 4127.0.0.1:6379> lrange list 0 -11) "one"2) "two"3) "one"4) "four"127.0.0.1:6379> lrem list 1 two #只移除一个two (精确匹配)(integer) 1127.0.0.1:6379> lrange list 0 -11) "one"2) "one"3) "four"127.0.0.1:6379> lrem list 2 one #移除两个one(integer) 2127.0.0.1:6379> lrange list 0 -11) "four"

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

截取list中的部分值

127.0.0.1:6379> rpush list hello1(integer) 1127.0.0.1:6379> rpush list hello2(integer) 2127.0.0.1:6379> rpush list hello3(integer) 3127.0.0.1:6379> rpush list hello4(integer) 4127.0.0.1:6379> ltrim list 1 2 #只截取其中索引1到2的元素,剩余的其他元素被移除,相当于Java中的trim方法OK127.0.0.1:6379> lrange list 0 -11) "hello2"2) "hello3"

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

rpoplpush 移除列表中的最后一个元素,并将该元素添加到另一个list的头部

127.0.0.1:6379> lrange list 0 -11) "hello1"2) "hello2"3) "hello3"4) "hello4"127.0.0.1:6379> rpoplpush list mylist #list为源list,mylist为目的list"hello4"127.0.0.1:6379> lrange list 0 -1 #原list中已将该值移除1) "hello1"2) "hello2"3) "hello3"127.0.0.1:6379> lrange mylist 0 -1 #新list中头部添加该值1) "hello4"

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

lset,将列表中指定下标的值替换为新的元素,当下标指定元素存在时,替换,不存在时,报错。

127.0.0.1:6379> lrange list 0 -11) "hello1"2) "hello2"3) "hello3"127.0.0.1:6379> lset list 1 helloOK127.0.0.1:6379> lrange list 0 -11) "hello1"2) "hello"3) "hello3"

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

linsert,在指定的元素前面或后面插入指定的元素。linsert的格式如下:linsert key BEFORE|AFTER pivot value ,由BEFORE|AFTER指定从前或从后插入, pivot指定list中具体元素的值,即从list的哪个元素的前或后插入,当list中存在多个pivot指定值,则选中下标小的元素

127.0.0.1:6379> lrange list 0 -11) "hello1"2) "hello"3) "hello3"127.0.0.1:6379> linsert list before hello hello2(integer) 4127.0.0.1:6379> linsert list after hello3 hello4(integer) 5127.0.0.1:6379> lrange list 0 -11) "hello1"2) "hello2"3) "hello"4) "hello3"5) "hello4"

小结:Redis中的链表实际上是一个链表,before Node after,left,right都可以进行值的插入,在两边插入或者值的改动,效率最高,中间元素,相对来说效率会相对来说低一些。

Redis Set

set是无需不重复集合,跟set有关的操作,命令前都有s

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

sadd,向set中插入值,set不存在时,创建set。smembers查询set集合中的所有元素

127.0.0.1:6379> sadd myset hello(integer) 1127.0.0.1:6379> sadd myset world(integer) 1127.0.0.1:6379> smembers myset1) "world"2) "hello"

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

判断元素是否是某set中的元素,值为0表示是set中的元素,值为1表示不是set中的元素

127.0.0.1:6379> smembers myset1) "world"2) "hello"127.0.0.1:6379> sismember myset maize(integer) 0127.0.0.1:6379> sismember myset hello(integer) 1

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

scard,获取当前set中元素的个数

127.0.0.1:6379> scard myset(integer) 2

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

srem,移除set中指定元素

127.0.0.1:6379> smembers myset1) "hello2"2) "hello1"3) "world"4) "hello"127.0.0.1:6379> srem myset hello(integer) 1127.0.0.1:6379> smembers myset1) "hello2"2) "hello1"3) "world"

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

srandmember,随机抽选出指定个数据的元素

127.0.0.1:6379> smembers myset1) "hello5"2) "hello6"3) "hello1"4) "hello2"5) "hello3"6) "hello"7) "world"8) "hello4"127.0.0.1:6379> srandmember myset #未指定个数时,默认为抽选出一个"hello5"127.0.0.1:6379> srandmember myset 2 #指定个数时,根据指定个数抽选元素1) "hello5"2) "hello2"127.0.0.1:6379> srandmember myset 21) "hello5"2) "hello"

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

spop,弹出元素

127.0.0.1:6379> smembers myset1) "hello5"2) "hello6"3) "hello1"4) "hello2"5) "hello3"6) "hello"7) "world"8) "hello4"127.0.0.1:6379> spop myset"hello6"127.0.0.1:6379> spop myset"world"127.0.0.1:6379> spop myset 21) "hello3"2) "hello"127.0.0.1:6379> smembers myset1) "hello5"2) "hello1"3) "hello2"4) "hello4"

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

smove,将指定值从源集合移动到目标集合中

127.0.0.1:6379> smembers myset1) "hello5"2) "hello1"3) "hello2"4) "hello4"127.0.0.1:6379> sadd myset2 maize cyj(integer) 2127.0.0.1:6379> smove myset myset2 hello1(integer) 1127.0.0.1:6379> smembers myset1) "hello5"2) "hello2"3) "hello4"127.0.0.1:6379> smembers myset21) "hello1"2) "maize"3) "cyj"

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

sdiff,两集合的差集

127.0.0.1:6379> smembers k11) "b"2) "d"3) "a"4) "c"127.0.0.1:6379> smembers k21) "g"2) "e"3) "f"4) "c"5) "d"127.0.0.1:6379> sdiff k1 k2 #所求为k1相当于k2的差集1) "b"2) "a"

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

sinter,两集合的交集

127.0.0.1:6379> smembers k11) "b"2) "d"3) "a"4) "c"127.0.0.1:6379> smembers k21) "g"2) "e"3) "f"4) "c"5) "d"127.0.0.1:6379> sinter k1 k21) "d"2) "c"

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

sunion,两集合的并集

127.0.0.1:6379> sunion k1 k21) "b"2) "g"3) "d"4) "a"5) "f"6) "c"7) "e"

Redis Hash

可以理解为一个map,在前面都是学习的key-value,这里是key-map,hash的命令是以h开头的,其命令和前面都是大同小异的

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

hash的存值和取值

127.0.0.1:6379> hset myhash field1 maize(integer) 1127.0.0.1:6379> hget myhash field1"maize"

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

hmset,hmget,同时设置和取出多个值

127.0.0.1:6379> hmset myhash field2 cyj field3 jOK127.0.0.1:6379> hmget myhash field1 field2 field31) "maize"2) "cyj"3) "j"

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

hgetall,获取hash中所有的值

127.0.0.1:6379> hgetall myhash1) "field1"2) "maize"3) "field2"4) "cyj"5) "field3"6) "j"

hdel删除hash中的元素,hlen计算hash的长度,hexists,判断hash中指定字段是否存在

hkeys,获取hash中所有字段(field),hvals,获取hash中所有的值(value)

Redis Zset(有序集合)

在set的基础上加上一个值,set k1 v1 zset k1 score1 v1

zset的命令以z开头

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

zset中添加一个值和添加多个值

127.0.0.1:6379> zadd myzset 1 one(integer) 1127.0.0.1:6379> zadd myzset 3 three 2 two(integer) 2127.0.0.1:6379> zrange myzset 0 -11) "one"2) "two"3) "three"

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

zset中元素的排序

127.0.0.1:6379> zrange myzset 0 -11) "one"2) "two"3) "three" 127.0.0.1:6379> zrangebyscore myzset -inf +inf #-inf表示负无穷,+inf表示正无穷,也可以写其他的取值范围1) "one"2) "two"3) "three"

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

zrem,移除有序集合zset中的指定元素

127.0.0.1:6379> zrange myzset 0 -11) "one"2) "two"3) "three"127.0.0.1:6379> zrem myzset three(integer) 1127.0.0.1:6379> zrange myzset 0 -11) "one"2) "two"

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

zcount,获取指定区间的成员数量

127.0.0.1:6379> zrange myzset 0 -11) "one"2) "two"3) "three"4) "four"5) "five"6) "six"7) "seven"127.0.0.1:6379> zcount myzset 0 5(integer) 5

有关Zset的命令可以在/commands.html#sorted_set查看

三种特殊数据类型

geospatial 地理位置

GEO只有六个命令

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

geoadd,添加地理位置 geoadd 【key】 【经度】 【纬度】 【城市名称】

规则:两极无法直接添加,我们一般会下载城市数据,直接通过java一次性导入

127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing(integer) 1127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai(integer) 1127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqing(integer) 1127.0.0.1:6379> geoadd china:city 114.08 22.54 shenzhen(integer) 1127.0.0.1:6379> geoadd china:city 120.15 30.28 hangzhou(integer) 1127.0.0.1:6379> geoadd china:city 108.94 34.26 xian(integer) 1

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

geopos,获取某个地址的地理位置,是一个坐标值

127.0.0.1:6379> geopos china:city beijing #获取指定城市的经度和纬度1) 1) "116.39999896287918"2) "39.900000091670925"127.0.0.1:6379> geopos china:city chongqing shanghai1) 1) "106.49999767541885"2) "29.529999579006592"2) 1) "121.47000163793564"2) "31.229999039757836"

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

geodist,获得两个地理位置之间的距离,如果两个位置其中一个不存在,命令返回空

127.0.0.1:6379> geodist china:city beijing chongqing"1464070.8051"127.0.0.1:6379> geodist china:city beijing chongqing km #计算北京和上海的km值"1464.0708"

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

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

用法:查找附近的人

georadius key longitude latitude radius m|km|ft|mi [WITHCOORD] [WITHDIST] [WITHHASH] [COUNT count] [ASC|DESC] [STORE key] [STOREDIST key] /developer/section/1374022

georadius 【key】 【经度】【纬度】【距离】【单位】【显示距离(可选)】【显示坐标(可选)】【count筛选几个用户】

127.0.0.1:6379> georadius china:city 110 30 1000 km1) "chongqing"2) "xian"3) "shenzhen"4) "hangzhou"127.0.0.1:6379> georadius china:city 110 30 800 km withcoord1) 1) "chongqing"2) 1) "106.49999767541885"2) "29.529999579006592"2) 1) "xian"2) 1) "108.9399978518486"2) "34.2599996441893"127.0.0.1:6379> georadius china:city 110 30 800 km withcoord withdist withhash1) 1) "chongqing"2) "341.9374" #距离3) (integer) 40260420916289844) 1) "106.49999767541885" #经度2) "29.529999579006592" #纬度2) 1) "xian"2) "484.2186"3) (integer) 40401153448913274) 1) "108.9399978518486"2) "34.2599996441893"

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

georadiusbymember,查找key中的城市的指定半径内的城市元素,会查询出自己

127.0.0.1:6379> georadiusbymember china:city beijing 1000 km withcoord withdist1) 1) "beijing"2) "0.0000"3) 1) "116.39999896287918"2) "39.900000091670925"2) 1) "xian"2) "911.3409"3) 1) "108.9399978518486"2) "34.2599996441893"

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

geohash,返回一个或多个元素的geohash表示(用的较少)

#将二维的经纬度转换为一维字符串,如果两个字符串越接近,那么距离越近127.0.0.1:6379> geohash china:city beijing chongqing1) "wx4fbxxfke0" 2) "wm5xzrybty0"

GEO 底层的实现原理起始就是Zset,我们可以使用zset命令来操作geo,例如查看范围内的元素,删除元素的命令等等

Hyperloglog

什么是基数?

集合A{1,3,5,7,8,7}

集合B{1,3,5,7,8}

基数(不重复元素)=5,可以接受误差

Redis Hyperloglog是基数统计算法,它最大的有点就是占用的内存是固定的,2^64不同的元素基数,只需要12kb的内存,从内存的角度来考虑,在集合不重复计数中,Hyperloglog是首选。

Hyperloglog的命令都是以PF开头的

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

PFadd,添加元素,PFCOUNT,元素计数(不重复的元素个数)

127.0.0.1:6379> PFadd mykey a b c d e f g h(integer) 1127.0.0.1:6379> PFCOUNT mykey(integer) 8

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

pfmerge,合并两个Hyperloglog的元素(取并集)

PFMERGE 【目标key】 【源keys,多个】

127.0.0.1:6379> PFadd mykey a b c d e f g h(integer) 1127.0.0.1:6379> PFCOUNT mykey(integer) 8127.0.0.1:6379> PFADD mykey2 g h i j k l m(integer) 1127.0.0.1:6379> PFCOUNT mykey2(integer) 7127.0.0.1:6379> PFMERGE mykey3 mykey mykey2OK127.0.0.1:6379> pfcount mykey3(integer) 13

Bitmaps

位存储

bitmaps位图,数据结构,都是操作二进制位来进行记录,只有0和1两个状态

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

setbit,存储bitmaps(这里应用场景是模拟一周登录情况)

127.0.0.1:6379> setbit sign 0 1(integer) 0127.0.0.1:6379> setbit sign 1 1(integer) 0127.0.0.1:6379> setbit sign 2 0(integer) 0127.0.0.1:6379> setbit sign 3 1(integer) 0127.0.0.1:6379> setbit sign 4 1(integer) 0127.0.0.1:6379> setbit sign 5 0(integer) 0127.0.0.1:6379> setbit sign 6 0(integer) 0

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

getbit,查看某天登录情况

127.0.0.1:6379> getbit sign 2(integer) 0

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

bitcount,统计打开天数

127.0.0.1:6379> bitcount sign #未指定范围,默认查询所有(integer) 4127.0.0.1:6379> bitcount sign 0 4(integer) 4

Redis事务

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

Redis单条命令是保证原子性的,但Redis事务是不保证原子性的,且Redis事务没有隔离基本别概念

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

Redis的事务:

​ 1、开启事务(multi)

​ 2、命令入队(…)

​ 3、执行事务(exec)

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

一次事务的执行过程(每次事务在exec就已经结束)

127.0.0.1:6379> multiOK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> get k2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> exec1) OK2) OK3) "v2"4) OK

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

DISCARD,放弃事务

127.0.0.1:6379> multiOK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> DISCARDOK127.0.0.1:6379> get k4 #事务队列中命令都不会被执行,k4未被存入(nil)

编译时错误(命令有错误),事务中所有的命令都不会被执行

127.0.0.1:6379> multiOK127.0.0.1:6379> set k1 v1QUEUED127.0.0.1:6379> set k2 v2QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> getset k3 #错误的命令(error) ERR wrong number of arguments for 'getset' command127.0.0.1:6379> set k4 v4QUEUED127.0.0.1:6379> exec #执行事务报错(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get k1 #所有的命令都没有执行(nil)

运行时错误(例如java中经常模拟的1/0),执行命令时,其他的命令是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> set k1 v1OK127.0.0.1:6379> set k2 v1OK127.0.0.1:6379> multiOK127.0.0.1:6379> incr k1 #对字符串进行+1操作,编译时不出错,运行时出错QUEUED127.0.0.1:6379> set k3 v3QUEUED127.0.0.1:6379> exec1) (error) ERR value is not an integer or out of range #命令报错2) OK #事务中其他语句正常执行127.0.0.1:6379> get k3 #语句执行成功,成功将字符串存入"v3"

监控

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

乐观锁:很乐观,认为什么时候都不会出问题,因此不会上锁,更新数据的时候判断一下,在此期间是否有人修改数据,在mysql中获取version,更新的时候比较version

Redis监视测试 (Redis的watch本身就是乐观锁)

正常执行成功

127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money #监视money对象OK127.0.0.1:6379> multi #事务正常结束,事务OK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby out 20QUEUED127.0.0.1:6379> exec1) (integer) 802) (integer) 20

事务执行失败

一个客户端监视了money,且已开启事务,并将命令入队,但并未执行

127.0.0.1:6379> watch moneyOK127.0.0.1:6379> multiOK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby money 20QUEUED

在另一个客户端,直接修改了money的值

127.0.0.1:6379> get money"100"127.0.0.1:6379> set money 120OK

这时在监视money的客户端执行事务,会发现事务返回为空,因为检测到money的值被修改,事务将执行失败

127.0.0.1:6379> exec(nil)

如果修改失败,先解锁,再重新获取锁

127.0.0.1:6379> unwatch #如果事务执行失败,就先解锁OK127.0.0.1:6379> watch money #获取最新的值,再次监视,select versionOK127.0.0.1:6379> multiOK127.0.0.1:6379> decrby money 10QUEUED127.0.0.1:6379> incrby out 10QUEUED127.0.0.1:6379> exec #比对监视的值是否发生改变,如果未发生改变,则执行成功,否则执行失败1) (integer) 902) (integer) 10

`

运行时错误(例如java中经常模拟的1/0),执行命令时,其他的命令是可以正常执行的,错误命令抛出异常

监控

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

乐观锁:很乐观,认为什么时候都不会出问题,因此不会上锁,更新数据的时候判断一下,在此期间是否有人修改数据,在mysql中获取version,更新的时候比较version

Redis监视测试 (Redis的watch本身就是乐观锁)

正常执行成功

127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money #监视money对象OK127.0.0.1:6379> multi #事务正常结束,事务OK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby out 20QUEUED127.0.0.1:6379> exec1) (integer) 802) (integer) 20

事务执行失败

一个客户端监视了money,且已开启事务,并将命令入队,但并未执行

127.0.0.1:6379> watch moneyOK127.0.0.1:6379> multiOK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby money 20QUEUED

在另一个客户端,直接修改了money的值

127.0.0.1:6379> get money"100"127.0.0.1:6379> set money 120OK

这时在监视money的客户端执行事务,会发现事务返回为空,因为检测到money的值被修改,事务将执行失败

127.0.0.1:6379> exec(nil)

如果修改失败,先解锁,再重新获取锁

127.0.0.1:6379> unwatch #如果事务执行失败,就先解锁OK127.0.0.1:6379> watch money #获取最新的值,再次监视,select versionOK127.0.0.1:6379> multiOK127.0.0.1:6379> decrby money 10QUEUED127.0.0.1:6379> incrby out 10QUEUED127.0.0.1:6379> exec #比对监视的值是否发生改变,如果未发生改变,则执行成功,否则执行失败1) (integer) 902) (integer) 10

期待指正哦😊

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。