Reids基础笔记 作者:哇塞大嘴好帅

Reids基础笔记 作者:哇塞大嘴好帅

1.概述

1.1 Redis是什么

Redis是一个开源的,内存中的数据结构存储系统,它可以作用**数据库**、**缓存**、**消息中间件**。它支持多种数据结构,如字符串(String)、散列(hashes)、集合(lists)、有序集合(sorted sets)与范围查询、butnaos、hyperloglogs和地理空间(geospatial)索引版经常哈寻,Redis内置了 复制(replication),LUA脚本(luascripting),LRU驱动事件(LRU eviction),事务(transactiobns)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentienl)和自动分区(Cluster)提供高可用性(high availability)

1.2 Reids能做什么

​ 1.内存存储,持久化。内存是断电就失去,所以说持久化很重化(rdb、aof)

​ 2.效率高,可以用于告诉缓存

​ 3.发布订阅系统

​ 4.吸毒信息分析

​ 5.计时器,计数器(如浏览量)

​ 6…

1.3 特性

1.多样化数据类型

2.集群

3.持久化

4.事务

2.安装

2.1 Windows下安装

​ 1.下载安装包:https://github.com/dmakic/redis/releases

​ 2.解压

​ 3.执行redis-server.exe启动服务

​ 4.使用reids-cli.exe客户端连接reids

​ 输入指令ping 如果返回个pong就代表连接成功

Reid文件介绍

redis-server.exe : redis启动服务

redis-cli.exe : redis客户端

redis-check-aof.exe : redis检查持久化文件是否正确

redis-benchmark.exe: redis测试性能

Redis推荐在Linux下使用

2.2 linux下的安装

参考Linux安装Redis的笔记

3.基本语法

Redis 命令手册: http://redis.cn/commands.html

查看是什么类型

type

查看剩余过期时间

ttl 键

设置数据过期时间 # 设置10秒后过期

expire name 10

从当前数据库移除此键

move 键 1

判断某个键是否存在,如果存在返回1 不存在返回0

exists 键

redis默认有16个数据库,在redis.conf中有个databases 16

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

select 2

查看当前数据库容量大小 当我们存入一个值 容量就+1

DBSIZE

查看数据库所有的key

keys *

清空当前库

flushdb

清空所有库

flushall

4.基础知识

4.1 Redis是单线程的

​ Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络的带宽,既然可以使用单线程实现就可以使用单线程了。

为什么单线程还这么快?

核心:redis是将所有的数据全部放在了内存中,所以使用单线程效率是最高的。

​ 多线程会产生CPU上下文切换,这是一个很耗时的操作,对于内存系统来说秒如果没有上下文切换效率就是最高的。多次读写都是在一个CPU上的,在内存的情况来看就是最佳方案。

5.常见五大数据类型

51 String(字符串类型)

设置值

set 键名 值

取值

get 键名

追加

append 键值 追加的内容

当我们追加成功会返回字符串的追加后的长度

如果我们的键不存在就会创建一个新的,就相当于set key

获取字符串长度

strlen 键

自增

127.0.0.1:6379> set num 0		# 设置num的值为0OK127.0.0.1:6379> get num			# 获取num的值"0"127.0.0.1:6379> incr num		# num自增1(integer) 1127.0.0.1:6379> get num			# 获取num的值."1"

自减

127.0.0.1:6379> set num 1		# 设置num为0OK		127.0.0.1:6379> get num			# 获取num的值"1"	127.0.0.1:6379> decr num		# 使得num自减1(integer) 0127.0.0.1:6379> get num			# 获取num的值"0"

步长 自增

127.0.0.1:6379> set num 1		# 设置num值为1OK127.0.0.1:6379> incrby num 9	# 让num加9(integer) 10127.0.0.1:6379> get num			# 获取num的值"10"

步长 自减

127.0.0.1:6379> set num 10		# 设置num值为10OK127.0.0.1:6379> DECRBY num 5	# 使num自减5(integer) 5

获取范围字符串

127.0.0.1:6379> set str1 "hello world"	# 设置值OK127.0.0.1:6379> get str1				# 取值"hello world"127.0.0.1:6379> GETRANGE str1 0 4		# 获取0-4的范围字符串"hello"127.0.0.1:6379> GETRANGE str1 0 -1		# 获取全部的字符串"hello world"

替换字符串

127.0.0.1:6379> set str2 abcdefg		# 设置值OK127.0.0.1:6379> get str2				# 获取值"abcdefg"127.0.0.1:6379> SETRANGE str2 1 xx		# 替换键值为str2的下标为1替换为xx,如果替换值的长度大于1,比如替换值长度为2那么就替换下标为1的位置数2位进行替换(integer) 7127.0.0.1:6379> get str2"axxdefg"

创建键并且设置过期时间

127.0.0.1:6379> SETEX str4 300 "hello"		# 创建键设置过期时间为300秒OK127.0.0.1:6379> get str4					# 获取键"hello"	127.0.0.1:6379> ttl str4					# 查看过期时间(integer) 276

创建减 如果该键不存在则创建 如果存在则创建失败

127.0.0.1:6379> setnx mykey "dazui"			# 创建键 并且判断该键是否存在 如果创建失败(integer) 1127.0.0.1:6379> get mykey"dazui"127.0.0.1:6379> setnx mykey "dazu666i"		# 创建键 该键已经存在创建失败(integer) 0127.0.0.1:6379> get mykey"dazui"

一次性设置多个值 批量设置 | 获取多个值 批量获取多个值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4	# 设置多个值OK127.0.0.1:6379> keys *1) "k4"2) "k1"3) "k2"4) "k3"####################################################################127.0.0.1:6379> mget k1 k2 k3 k4 			   # 获取多个值1) "v1"2) "v2"3) "v3"4) "v4"####################################################################127.0.0.1:6379> mset k1 v2 k2 v3OK127.0.0.1:6379> msetnx k1 v3 k2 v4				# 如果设置的键存在就创建失败(integer) 0

创建对象

127.0.0.1:6379> mset user:1:name "dazui" user:1:age 18		#创建user对象1 名字为dazui  年龄为18OK127.0.0.1:6379> mget user:1:name user:1:age					#获取user对象1 名字和  age信息1) "dazui"2) "18"127.0.0.1:6379

getset 使用 可以用于更新

127.0.0.1:6379> getset name dazuizui		#设置name值 如果该值没值就获取null  如果有值就获取之前的值并且替换(nil)127.0.0.1:6379> get name"dazuizui"127.0.0.1:6379> getset name wasaidazuihaoshuai		#获取之前的值 并且将新值覆盖"dazuizui"

5.2 list(列表)

list插入值 查询值

127.0.0.1:6379> rpush list 1		# 右插入一个数据(integer) 1127.0.0.1:6379> rpush list 2		# 右插入一个数据(integer) 2127.0.0.1:6379> lpush list 0		# 左插入一个数据(integer) 3127.0.0.1:6379> lrange list 0 -1	# 查询所有数据1) "0"2) "1"3) "2"

移除值

127.0.0.1:6379> lpop list  			# 移除左侧第一个值"0"127.0.0.1:6379> rpop list 			# 移除右侧第一个值"2"127.0.0.1:6379> lrange list 0 -1	# 查询所有数据1) "1"127.0.0.1:6379> 

获取指定下标的数据

127.0.0.1:6379> lindex list 1		# 获取指定下标为1的数据"2"	127.0.0.1:6379> lindex list 0		# 获取指定下标为0的数据"1"127.0.0.1:6379> lindex list 5		# 获取指定下标为5的手机壳(nil)

获取队列的长度

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

移除指定的值

127.0.0.1:6379> lrange list 0 -1	# 获取值1) "1"2) "2"3) "3"4) "4"5) "4"6) "4"7) "4"127.0.0.1:6379> lrem list 1 "4"		# 移除一个元素并且值为4(integer) 1127.0.0.1:6379> lrem list 2 "4"		# 移除凉饿元素并且值为4(integer) 2

保留指定下标区间的数据

127.0.0.1:6379> lrange list 0 -1	# 获取所有数据1) "1"2) "2"3) "3"4) "4"127.0.0.1:6379> ltrim list 1 2		# 只保留指定下标区间的数据 其他数据都被截取OK127.0.0.1:6379> lrange list 0 -1	# 获取所有数据1) "2"2) "3"

移动列表最后一个元素,将他移动到其他列表中

127.0.0.1:6379> lrange list 0 -1		# 获取list表所有数据1) "2"2) "3"127.0.0.1:6379> rpoplpush list list1	# 将list列表右侧第一个数据移至到新的列表中"3"127.0.0.1:6379> lrange list1 0 -1		# 查询list1列表所有数据 1) "3"

指定下标添加值

127.0.0.1:6379> lpush list 0		# 左插入一个数据(integer) 1127.0.0.1:6379> exists list			# 判断键是否存在(integer) 1127.0.0.1:6379> exists list1		# 判断键是否存在(integer) 0127.0.0.1:6379> lset list 0 dazui	# 向list集合下标为0的地方插入值,如果下标0的位置已有值就会被替换OK									# 插入成功127.0.0.1:6379> lset list1 0 dazui	# 向list1集合下标为0的地方插入值(error) ERR no such key				# 插入失败,因为list1键值不存在127.0.0.1:6379> lrange list 0 -1	# 查询数1) "dazui"

在指定值得前方或者后方插入一个值

127.0.0.1:6379> lrange list 0 -1								# 查询所有制1) "dazui"127.0.0.1:6379> LINSERT list before "dazui" "hello"				# 在dazui字符串前方插入一个字符(integer) 2127.0.0.1:6379> lrange list 0 -1								# 查询所有字符1) "hello"2) "dazui"127.0.0.1:6379> linsert list after "dazui" "haoshuai"			# 在dazui字符串后方插入一个字符(integer) 3127.0.0.1:6379> lrange list 0 -1								# 查看所有字符1) "hello"2) "dazui"3) "haoshuai"

5.3 set集合

​ set的值不可以重复,也是无序的

添加元素

127.0.0.1:6379> sadd sei "hello"  # 添加值(integer) 1127.0.0.1:6379> sadd sei "dazui"  # 添加值(integer) 1

查询所有值

127.0.0.1:6379> smembers sei1) "dazui"2) "hello"

查看元素是否存在

127.0.0.1:6379> sismember sei hello		# 查看元素是否存在,如果存在返回1(integer) 1127.0.0.1:6379> sismember sei hello1	# 查看元素知否存在,如果存在返回0(integer) 0

查看集合个数

127.0.0.1:6379> scard sei				# 查询是否存在(integer) 2

删除指定元素

127.0.0.1:6379> srem sei hello			# 移除指定元素(integer) 1

随机获取元素

127.0.0.1:6379> smembers sei			# 查询所有元素1) "hello"2) "dazui"127.0.0.1:6379> SRANDMEMBER sei			# 随机获取一个元素"dazui"

随机删除指定的key

127.0.0.1:6379> spop sei				# 随机删除一个值"dazui"127.0.0.1:6379> 

将一个值引用到另一个集合

127.0.0.1:6379> smove sei myset "dazui"# 将sei里的dazui元素移至到myset元素(integer) 1127.0.0.1:6379> SMEMBERS myset			# 查询myset集合1) "dazui"127.0.0.1:6379> smembers sei			# 查询sei集合1) "hello"127.0.0.1:6379> 

查询两个集合之间的差集

127.0.0.1:6379> smembers sei 			# 查询sei集合1) "dazui"2) "hello"127.0.0.1:6379> smembers myset			# 查询myset集合1) "dazui"127.0.0.1:6379> sdiff sei myset			# 查询他们的差集1) "hello"

查询两个集合的交集

127.0.0.1:6379> sinter myset sei		# 查询交集1) "dazui

查询两个集合的合集

127.0.0.1:6379> SUNION sei myset		# 查询合集1) "hello"2) "dazui"127.0.0.1:6379> 

5.4 Hash (哈希)

添加 获取

127.0.0.1:6379> hset hash1 k1 12		# hash名叫hash1 键值叫k1 值为12(integer) 1127.0.0.1:6379> hset hash1 k2 13 k3 14  # 设置多个值(integer) 2127.0.0.1:6379> hget hash1 k1			# 获取指定值"12"127.0.0.1:6379> hmget hash1 k2 k3		# 获取多个指定值1) "13"2) "14"

删除指定值 获取全部之

127.0.0.1:6379> hdel hash1 k1			# 删除指定值(integer) 1127.0.0.1:6379> hgetall hash1			# 获取全部键值对1) "k2"2) "13"3) "k3"4) "14"

获取hash表的长度

127.0.0.1:6379> hlen hash1				# 获取长度(integer) 2

获取指定键是否存在

127.0.0.1:6379> HEXISTS hash1 k2		# 判断指定键是否存在(integer) 1

获取所有的键 获取所有的值

127.0.0.1:6379> hkeys hash1				# 查看所有键1) "k2"2) "k3"127.0.0.1:6379> HVALS hash1				# 查看所有值1) "13"2) "14"

自增自减

 127.0.0.1:6379> hincrby hash1 k2 2(integer) 15127.0.0.1:6379> hincrby hash1 k3 -2(integer) 12127.0.0.1:6379> hvals hash11) "15"2) "12"

5.5 Zset(有序集合)

127.0.0.1:6379> zadd key1 1 one				# 将下标为1的地方添加数据(integer) 1127.0.0.1:6379> zadd key1 2 two				# 将下标为2的地方添加数据(integer) 1127.0.0.1:6379> zadd key1 2  three			# 将下标为2的地方添加数据 如果下标为2的地方有数据 下标为2的数据向后移动,将新数据放在下标为2的最前方, 当前下标为2的数据有three two(integer) 1127.0.0.1:6379> zrange key 0 -1(empty array)127.0.0.1:6379> zrange key1 0 -11) "one"2) "three"3) "two"127.0.0.1:6379> 

查询所有数据并且带序号

127.0.0.1:6379> zrangebyscore key1 -inf +inf withscores			# 查询所有数据并且带序号1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"

查看小于某个序号的值

127.0.0.1:6379> zrangebyscore key1 -inf 2 withscores			# 查询小于2的所值,并且打印序号	1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"127.0.0.1:6379> zrangebyscore key1 -inf +inf					# 查询小于2的的数据1) "one"2) "three"3) "two"

移除指定元素元素

127.0.0.1:6379> zrem key1 two									# 移除指定元素two(integer) 1	

查看多少个元素

127.0.0.1:6379> zcard key1										# 获取有序集合的格式(integer) 3

查看从大到小序号的值

127.0.0.1:6379> zrevrange key1 0 -1 withscores					# 查询从大到小的序号的值1) "two"2) "5"3) "five"4) "5"5) "three"6) "2"7) "one"8) "1"

查看区间的值有几个

127.0.0.1:6379> zrange key1 0 -1 withscores						# 查看所有值并且显示序号1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"7) "five"8) "5"127.0.0.1:6379> zcount key1 0 3									# 查询0-3区间的值有几个(integer) 3

6.三种特殊数据类型

6.1 geospatial (地理位置)

geospatial可以存放城市维度

有效精度 -180度到 180度

有效维度-85.05112878度到85.05112878度

**维度查询网站:**http://www.jsons.cn/lngcode/

添加地理位置

127.0.0.1:6379> geoadd HongKong:city 115.164167 22.2664163 hongkong				# 插入HongKong的维度(integer) 1127.0.0.1:6379> geoadd HongKong:city 114.17495 22.327115 jiulong				# 插入HongKong JiuLong的维度(integer) 1

获取指定城市坐标

127.0.0.1:6379> geopos HongKong:city jiulong									# 获取HongKong JiuLong的经度纬度1) 1) "114.17495101690292358"   2) "22.3271154118881654"

两个位置的距离

127.0.0.1:6379> geodist HongKong:city hongkong jiulong km						# 查看两者之间的距离"102.0236"

m标识单位为米

km表示单位为千米

mi标识单位为英里

ft标识单位为英尺

附近的人

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

127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 100 km1) "jlc"2) "hongkong"127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 1000 km1) "jiulong"2) "jlc"3) "hongkong"

以位置为中心附近的位置

127.0.0.1:6379> georadiusbymember HongKong:city hongkong 100 km					# 查看hongkong周围100km的城市1) "jlc"2) "hongkong"

6.2Hyperloglog(基数统计)

做什么?

​ 如果允许容错,可以使用Hyperloglog进行计数

什么是基数

​ A{1,3,5,7,8,9} B{1,3,5,7}

​ 就是查找不重复的元素

基本使用

127.0.0.1:6379> pfadd key3 a b b3 d f g h i j k									# 添加数据(integer) 1127.0.0.1:6379> pfcount key3													# 查询数据返回长度(integer) 10127.0.0.1:6379> pfadd key2 i j k z x c v b n									# 添加数据(integer) 1127.0.0.1:6379> pfmerge key key2 key3											# 合并key3 key2的数据返回给keyOK127.0.0.1:6379> pfcount key 													# 查询key长度,Hyperloglog重复的数据会添加失败(integer) 15127.0.0.1:6379> pfadd key3 qw													# 添加数据(integer) 1127.0.0.1:6379> pfcount key3													# 查询数据返回长度(integer) 11

6.3 Bitmaps(位图)

​ 他的值只有0和1

​ 就来做个签到系统为案例

设置值 --0为未签到1为签到

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

查看值 --如果返回0为未签到如果返回1为签到

127.0.0.1:6379> getbit bhk 4(integer) 0127.0.0.1:6379> getbit bhk 6(integer) 1

查看为1的数据

127.0.0.1:6379> bitcount bhk (integer) 4

7.基本的事务操作

7.1事务

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

​ **特性:**一次性、顺序性、排他性!

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

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

Redis单条命令保存原子性,事务不保证原子性。

7.2 Redis的事务

1.开启事务(multi)

127.0.0.1:6379> multi 								# 开启事务OK

2.命令入队 (写命令)

# 命令入队127.0.0.1:6379> set name dazui QUEUED127.0.0.1:6379> set age 18QUEUED

3.执行事务 (exec)

127.0.0.1:6379> exec								# 执行1) OK

正常执行事务!

127.0.0.1:6379> multi 								# 开启事务OK127.0.0.1:6379> set name dazui						# 命令入队QUEUED127.0.0.1:6379> exec								# 执行事务1) OK

放弃事务

127.0.0.1:6379> multi								# 开启事务OK127.0.0.1:6379> set k1 a							# 命令入列QUEUED127.0.0.1:6379> set k2 a							# 命令入列QUEUED127.0.0.1:6379> DISCARD								# 放弃事务OK127.0.0.1:6379> get k1								# 获取String数据(nil)

编译型异常

代码有问题或者命令有错误

​ 如果触发了事务中所有命令都不会执行

127.0.0.1:6379> multi								# 创建事务OK127.0.0.1:6379> set a1 aQUEUED127.0.0.1:6379> set a2 aQUEUED127.0.0.1:6379> set a3 aQUEUED127.0.0.1:6379> getset a1							# 错误命令入列(error) ERR wrong number of arguments for 'getset' command127.0.0.1:6379> set a4 4QUEUED127.0.0.1:6379> exec								# 执行事务,报错(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get a1								# 证明了所有的命令都没有被执行(nil)

运行时异常

​ 比如1/0报错,如果事务队列中存在余发星,那么执行命令的时候其他命令都是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> multi								# 创建事务OK127.0.0.1:6379> set k1 "v1"							# 设置值 加入命令队列QUEUED127.0.0.1:6379> incr k1								# 对k1进行自加1,但是k1存放的的数据不是纯数字,就会报错	加入队列QUEUED127.0.0.1:6379> set k2 12							# 设置值 加入队列QUEUED127.0.0.1:6379> exec								# 执行事务1) OK2) (error) ERR value is not an integer or out of range3) OK127.0.0.1:6379> get k2								# 获取k2数据 证明运行时异常其他命令可以正常执行。"12"

8.加锁

8.1 悲观锁

​ 悲观锁认为什么时候都会出问题,无论做什么都会加锁。这样做特别影响性能。

8.2 乐观锁

​ 他认为什么时候都不会出现问题。更新数据的时候去判断下,在此期间是否有人修改过这个数据。

8.3 监视

正常执行

127.0.0.1:6379> set money 100									# 设置100块钱OK127.0.0.1:6379> set out 0										# 设置花出去的钱OK127.0.0.1:6379> watch money										# 监视OK127.0.0.1:6379> MULTI											# 创建事务OK127.0.0.1:6379> decrby money 20									# 钱自减20QUEUED	127.0.0.1:6379> incrby out 20									# 花出去的钱自增20QUEUED127.0.0.1:6379> exec											# 执行1) (integer) 802) (integer) 20

并发情况

线程A

127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money										# 监视OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby money 20QUEUED127.0.0.1:6379> exec											# 执行 一定要在线程B执行完再去执行 为什么失败?因为在在执行事务他会比较money跟监视时候的值是否相同,如果相同就可以执行,不相同就执行失败,这时候线程B修改了money的值,所以更新失败(nil)

线程B

127.0.0.1:6379> set money 10000OK

放弃监视 解锁

127.0.0.1:6379> UNWATCH											# 取消加锁OK

9.番外

1.为什么Reids是6379

Alessia Merz 是一位意大利舞女、女演员。 Redis 作者 Antirez 早年看电视节目,觉得 Merz 在节目中的一些话愚蠢可笑,Antirez 喜欢造“梗”用于平时和朋友们交流,于是造了一个词 “MERZ”,形容愚蠢,与 “stupid” 含义相同。

后来 Antirez 重新定义了 “MERZ” ,形容”具有很高的技术价值,包含技艺、耐心和劳动,但仍然保持简单本质“。

到了给 Redis 选择一个数字作为默认端口号时,Antirez 没有多想,把 “MERZ” 在手机键盘上对应的数字 6379 拿来用了。

​ # Reids 5.08 版本

1.概述

1.1 Redis是什么

Redis是一个开源的,内存中的数据结构存储系统,它可以作用**数据库**、**缓存**、**消息中间件**。它支持多种数据结构,如字符串(String)、散列(hashes)、集合(lists)、有序集合(sorted sets)与范围查询、butnaos、hyperloglogs和地理空间(geospatial)索引版经常哈寻,Redis内置了 复制(replication),LUA脚本(luascripting),LRU驱动事件(LRU eviction),事务(transactiobns)和不同级别的磁盘持久化(persistence),并通过Redis哨兵(Sentienl)和自动分区(Cluster)提供高可用性(high availability)

1.2 Reids能做什么

​ 1.内存存储,持久化。内存是断电就失去,所以说持久化很重化(rdb、aof)

​ 2.效率高,可以用于告诉缓存

​ 3.发布订阅系统

​ 4.吸毒信息分析

​ 5.计时器,计数器(如浏览量)

​ 6…

1.3 特性

1.多样化数据类型

2.集群

3.持久化

4.事务

2.安装

2.1 Windows下安装

​ 1.下载安装包:https://github.com/dmakic/redis/releases

​ 2.解压

​ 3.执行redis-server.exe启动服务

​ 4.使用reids-cli.exe客户端连接reids

​ 输入指令ping 如果返回个pong就代表连接成功

Reid文件介绍

redis-server.exe : redis启动服务

redis-cli.exe : redis客户端

redis-check-aof.exe : redis检查持久化文件是否正确

redis-benchmark.exe: redis测试性能

Redis推荐在Linux下使用

2.2 linux下的安装

参考Linux安装Redis的笔记

3.基本语法

Redis 命令手册: http://redis.cn/commands.html

查看是什么类型

type

查看剩余过期时间

ttl 键

设置数据过期时间 # 设置10秒后过期

expire name 10

从当前数据库移除此键

move 键 1

判断某个键是否存在,如果存在返回1 不存在返回0

exists 键

redis默认有16个数据库,在redis.conf中有个databases 16

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

select 2

查看当前数据库容量大小 当我们存入一个值 容量就+1

DBSIZE

查看数据库所有的key

keys *

清空当前库

flushdb

清空所有库

flushall

4.基础知识

4.1 Redis是单线程的

​ Redis是基于内存操作的,CPU不是Redis的性能瓶颈,Redis的瓶颈是根据机器的内存和网络的带宽,既然可以使用单线程实现就可以使用单线程了。

为什么单线程还这么快?

核心:redis是将所有的数据全部放在了内存中,所以使用单线程效率是最高的。

​ 多线程会产生CPU上下文切换,这是一个很耗时的操作,对于内存系统来说秒如果没有上下文切换效率就是最高的。多次读写都是在一个CPU上的,在内存的情况来看就是最佳方案。

5.常见五大数据类型

51 String(字符串类型)

设置值

set 键名 值

取值

get 键名

追加

append 键值 追加的内容

当我们追加成功会返回字符串的追加后的长度

如果我们的键不存在就会创建一个新的,就相当于set key

获取字符串长度

strlen 键

自增

127.0.0.1:6379> set num 0		# 设置num的值为0OK127.0.0.1:6379> get num			# 获取num的值"0"127.0.0.1:6379> incr num		# num自增1(integer) 1127.0.0.1:6379> get num			# 获取num的值."1"

自减

127.0.0.1:6379> set num 1		# 设置num为0OK		127.0.0.1:6379> get num			# 获取num的值"1"	127.0.0.1:6379> decr num		# 使得num自减1(integer) 0127.0.0.1:6379> get num			# 获取num的值"0"

步长 自增

127.0.0.1:6379> set num 1		# 设置num值为1OK127.0.0.1:6379> incrby num 9	# 让num加9(integer) 10127.0.0.1:6379> get num			# 获取num的值"10"

步长 自减

127.0.0.1:6379> set num 10		# 设置num值为10OK127.0.0.1:6379> DECRBY num 5	# 使num自减5(integer) 5

获取范围字符串

127.0.0.1:6379> set str1 "hello world"	# 设置值OK127.0.0.1:6379> get str1				# 取值"hello world"127.0.0.1:6379> GETRANGE str1 0 4		# 获取0-4的范围字符串"hello"127.0.0.1:6379> GETRANGE str1 0 -1		# 获取全部的字符串"hello world"

替换字符串

127.0.0.1:6379> set str2 abcdefg		# 设置值OK127.0.0.1:6379> get str2				# 获取值"abcdefg"127.0.0.1:6379> SETRANGE str2 1 xx		# 替换键值为str2的下标为1替换为xx,如果替换值的长度大于1,比如替换值长度为2那么就替换下标为1的位置数2位进行替换(integer) 7127.0.0.1:6379> get str2"axxdefg"

创建键并且设置过期时间

127.0.0.1:6379> SETEX str4 300 "hello"		# 创建键设置过期时间为300秒OK127.0.0.1:6379> get str4					# 获取键"hello"	127.0.0.1:6379> ttl str4					# 查看过期时间(integer) 276

创建减 如果该键不存在则创建 如果存在则创建失败

127.0.0.1:6379> setnx mykey "dazui"			# 创建键 并且判断该键是否存在 如果创建失败(integer) 1127.0.0.1:6379> get mykey"dazui"127.0.0.1:6379> setnx mykey "dazu666i"		# 创建键 该键已经存在创建失败(integer) 0127.0.0.1:6379> get mykey"dazui"

一次性设置多个值 批量设置 | 获取多个值 批量获取多个值

127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 k4 v4	# 设置多个值OK127.0.0.1:6379> keys *1) "k4"2) "k1"3) "k2"4) "k3"####################################################################127.0.0.1:6379> mget k1 k2 k3 k4 			   # 获取多个值1) "v1"2) "v2"3) "v3"4) "v4"####################################################################127.0.0.1:6379> mset k1 v2 k2 v3OK127.0.0.1:6379> msetnx k1 v3 k2 v4				# 如果设置的键存在就创建失败(integer) 0

创建对象

127.0.0.1:6379> mset user:1:name "dazui" user:1:age 18		#创建user对象1 名字为dazui  年龄为18OK127.0.0.1:6379> mget user:1:name user:1:age					#获取user对象1 名字和  age信息1) "dazui"2) "18"127.0.0.1:6379

getset 使用 可以用于更新

127.0.0.1:6379> getset name dazuizui		#设置name值 如果该值没值就获取null  如果有值就获取之前的值并且替换(nil)127.0.0.1:6379> get name"dazuizui"127.0.0.1:6379> getset name wasaidazuihaoshuai		#获取之前的值 并且将新值覆盖"dazuizui"

5.2 list(列表)

list插入值 查询值

127.0.0.1:6379> rpush list 1		# 右插入一个数据(integer) 1127.0.0.1:6379> rpush list 2		# 右插入一个数据(integer) 2127.0.0.1:6379> lpush list 0		# 左插入一个数据(integer) 3127.0.0.1:6379> lrange list 0 -1	# 查询所有数据1) "0"2) "1"3) "2"

移除值

127.0.0.1:6379> lpop list  			# 移除左侧第一个值"0"127.0.0.1:6379> rpop list 			# 移除右侧第一个值"2"127.0.0.1:6379> lrange list 0 -1	# 查询所有数据1) "1"127.0.0.1:6379> 

获取指定下标的数据

127.0.0.1:6379> lindex list 1		# 获取指定下标为1的数据"2"	127.0.0.1:6379> lindex list 0		# 获取指定下标为0的数据"1"127.0.0.1:6379> lindex list 5		# 获取指定下标为5的手机壳(nil)

获取队列的长度

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

移除指定的值

127.0.0.1:6379> lrange list 0 -1	# 获取值1) "1"2) "2"3) "3"4) "4"5) "4"6) "4"7) "4"127.0.0.1:6379> lrem list 1 "4"		# 移除一个元素并且值为4(integer) 1127.0.0.1:6379> lrem list 2 "4"		# 移除凉饿元素并且值为4(integer) 2

保留指定下标区间的数据

127.0.0.1:6379> lrange list 0 -1	# 获取所有数据1) "1"2) "2"3) "3"4) "4"127.0.0.1:6379> ltrim list 1 2		# 只保留指定下标区间的数据 其他数据都被截取OK127.0.0.1:6379> lrange list 0 -1	# 获取所有数据1) "2"2) "3"

移动列表最后一个元素,将他移动到其他列表中

127.0.0.1:6379> lrange list 0 -1		# 获取list表所有数据1) "2"2) "3"127.0.0.1:6379> rpoplpush list list1	# 将list列表右侧第一个数据移至到新的列表中"3"127.0.0.1:6379> lrange list1 0 -1		# 查询list1列表所有数据 1) "3"

指定下标添加值

127.0.0.1:6379> lpush list 0		# 左插入一个数据(integer) 1127.0.0.1:6379> exists list			# 判断键是否存在(integer) 1127.0.0.1:6379> exists list1		# 判断键是否存在(integer) 0127.0.0.1:6379> lset list 0 dazui	# 向list集合下标为0的地方插入值,如果下标0的位置已有值就会被替换OK									# 插入成功127.0.0.1:6379> lset list1 0 dazui	# 向list1集合下标为0的地方插入值(error) ERR no such key				# 插入失败,因为list1键值不存在127.0.0.1:6379> lrange list 0 -1	# 查询数1) "dazui"

在指定值得前方或者后方插入一个值

127.0.0.1:6379> lrange list 0 -1								# 查询所有制1) "dazui"127.0.0.1:6379> LINSERT list before "dazui" "hello"				# 在dazui字符串前方插入一个字符(integer) 2127.0.0.1:6379> lrange list 0 -1								# 查询所有字符1) "hello"2) "dazui"127.0.0.1:6379> linsert list after "dazui" "haoshuai"			# 在dazui字符串后方插入一个字符(integer) 3127.0.0.1:6379> lrange list 0 -1								# 查看所有字符1) "hello"2) "dazui"3) "haoshuai"

5.3 set集合

​ set的值不可以重复,也是无序的

添加元素

127.0.0.1:6379> sadd sei "hello"  # 添加值(integer) 1127.0.0.1:6379> sadd sei "dazui"  # 添加值(integer) 1

查询所有值

127.0.0.1:6379> smembers sei1) "dazui"2) "hello"

查看元素是否存在

127.0.0.1:6379> sismember sei hello		# 查看元素是否存在,如果存在返回1(integer) 1127.0.0.1:6379> sismember sei hello1	# 查看元素知否存在,如果存在返回0(integer) 0

查看集合个数

127.0.0.1:6379> scard sei				# 查询是否存在(integer) 2

删除指定元素

127.0.0.1:6379> srem sei hello			# 移除指定元素(integer) 1

随机获取元素

127.0.0.1:6379> smembers sei			# 查询所有元素1) "hello"2) "dazui"127.0.0.1:6379> SRANDMEMBER sei			# 随机获取一个元素"dazui"

随机删除指定的key

127.0.0.1:6379> spop sei				# 随机删除一个值"dazui"127.0.0.1:6379> 

将一个值引用到另一个集合

127.0.0.1:6379> smove sei myset "dazui"# 将sei里的dazui元素移至到myset元素(integer) 1127.0.0.1:6379> SMEMBERS myset			# 查询myset集合1) "dazui"127.0.0.1:6379> smembers sei			# 查询sei集合1) "hello"127.0.0.1:6379> 

查询两个集合之间的差集

127.0.0.1:6379> smembers sei 			# 查询sei集合1) "dazui"2) "hello"127.0.0.1:6379> smembers myset			# 查询myset集合1) "dazui"127.0.0.1:6379> sdiff sei myset			# 查询他们的差集1) "hello"

查询两个集合的交集

127.0.0.1:6379> sinter myset sei		# 查询交集1) "dazui

查询两个集合的合集

127.0.0.1:6379> SUNION sei myset		# 查询合集1) "hello"2) "dazui"127.0.0.1:6379> 

5.4 Hash (哈希)

添加 获取

127.0.0.1:6379> hset hash1 k1 12		# hash名叫hash1 键值叫k1 值为12(integer) 1127.0.0.1:6379> hset hash1 k2 13 k3 14  # 设置多个值(integer) 2127.0.0.1:6379> hget hash1 k1			# 获取指定值"12"127.0.0.1:6379> hmget hash1 k2 k3		# 获取多个指定值1) "13"2) "14"

删除指定值 获取全部之

127.0.0.1:6379> hdel hash1 k1			# 删除指定值(integer) 1127.0.0.1:6379> hgetall hash1			# 获取全部键值对1) "k2"2) "13"3) "k3"4) "14"

获取hash表的长度

127.0.0.1:6379> hlen hash1				# 获取长度(integer) 2

获取指定键是否存在

127.0.0.1:6379> HEXISTS hash1 k2		# 判断指定键是否存在(integer) 1

获取所有的键 获取所有的值

127.0.0.1:6379> hkeys hash1				# 查看所有键1) "k2"2) "k3"127.0.0.1:6379> HVALS hash1				# 查看所有值1) "13"2) "14"

自增自减

 127.0.0.1:6379> hincrby hash1 k2 2(integer) 15127.0.0.1:6379> hincrby hash1 k3 -2(integer) 12127.0.0.1:6379> hvals hash11) "15"2) "12"

5.5 Zset(有序集合)

127.0.0.1:6379> zadd key1 1 one				# 将下标为1的地方添加数据(integer) 1127.0.0.1:6379> zadd key1 2 two				# 将下标为2的地方添加数据(integer) 1127.0.0.1:6379> zadd key1 2  three			# 将下标为2的地方添加数据 如果下标为2的地方有数据 下标为2的数据向后移动,将新数据放在下标为2的最前方, 当前下标为2的数据有three two(integer) 1127.0.0.1:6379> zrange key 0 -1(empty array)127.0.0.1:6379> zrange key1 0 -11) "one"2) "three"3) "two"127.0.0.1:6379> 

查询所有数据并且带序号

127.0.0.1:6379> zrangebyscore key1 -inf +inf withscores			# 查询所有数据并且带序号1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"

查看小于某个序号的值

127.0.0.1:6379> zrangebyscore key1 -inf 2 withscores			# 查询小于2的所值,并且打印序号	1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"127.0.0.1:6379> zrangebyscore key1 -inf +inf					# 查询小于2的的数据1) "one"2) "three"3) "two"

移除指定元素元素

127.0.0.1:6379> zrem key1 two									# 移除指定元素two(integer) 1	

查看多少个元素

127.0.0.1:6379> zcard key1										# 获取有序集合的格式(integer) 3

查看从大到小序号的值

127.0.0.1:6379> zrevrange key1 0 -1 withscores					# 查询从大到小的序号的值1) "two"2) "5"3) "five"4) "5"5) "three"6) "2"7) "one"8) "1"

查看区间的值有几个

127.0.0.1:6379> zrange key1 0 -1 withscores						# 查看所有值并且显示序号1) "one"2) "1"3) "three"4) "2"5) "two"6) "2"7) "five"8) "5"127.0.0.1:6379> zcount key1 0 3									# 查询0-3区间的值有几个(integer) 3

6.三种特殊数据类型

6.1 geospatial (地理位置)

geospatial可以存放城市维度

有效精度 -180度到 180度

有效维度-85.05112878度到85.05112878度

**维度查询网站:**http://www.jsons.cn/lngcode/

添加地理位置

127.0.0.1:6379> geoadd HongKong:city 115.164167 22.2664163 hongkong				# 插入HongKong的维度(integer) 1127.0.0.1:6379> geoadd HongKong:city 114.17495 22.327115 jiulong				# 插入HongKong JiuLong的维度(integer) 1

获取指定城市坐标

127.0.0.1:6379> geopos HongKong:city jiulong									# 获取HongKong JiuLong的经度纬度1) 1) "114.17495101690292358"   2) "22.3271154118881654"

两个位置的距离

127.0.0.1:6379> geodist HongKong:city hongkong jiulong km						# 查看两者之间的距离"102.0236"

m标识单位为米

km表示单位为千米

mi标识单位为英里

ft标识单位为英尺

附近的人

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

127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 100 km1) "jlc"2) "hongkong"127.0.0.1:6379> georadius HongKong:city 115.164167 22.2664163 1000 km1) "jiulong"2) "jlc"3) "hongkong"

以位置为中心附近的位置

127.0.0.1:6379> georadiusbymember HongKong:city hongkong 100 km					# 查看hongkong周围100km的城市1) "jlc"2) "hongkong"

6.2Hyperloglog(基数统计)

做什么?

​ 如果允许容错,可以使用Hyperloglog进行计数

什么是基数

​ A{1,3,5,7,8,9} B{1,3,5,7}

​ 就是查找不重复的元素

基本使用

127.0.0.1:6379> pfadd key3 a b b3 d f g h i j k									# 添加数据(integer) 1127.0.0.1:6379> pfcount key3													# 查询数据返回长度(integer) 10127.0.0.1:6379> pfadd key2 i j k z x c v b n									# 添加数据(integer) 1127.0.0.1:6379> pfmerge key key2 key3											# 合并key3 key2的数据返回给keyOK127.0.0.1:6379> pfcount key 													# 查询key长度,Hyperloglog重复的数据会添加失败(integer) 15127.0.0.1:6379> pfadd key3 qw													# 添加数据(integer) 1127.0.0.1:6379> pfcount key3													# 查询数据返回长度(integer) 11

6.3 Bitmaps(位图)

​ 他的值只有0和1

​ 就来做个签到系统为案例

设置值 --0为未签到1为签到

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

查看值 --如果返回0为未签到如果返回1为签到

127.0.0.1:6379> getbit bhk 4(integer) 0127.0.0.1:6379> getbit bhk 6(integer) 1

查看为1的数据

127.0.0.1:6379> bitcount bhk (integer) 4

7.基本的事务操作

7.1事务

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

​ **特性:**一次性、顺序性、排他性!

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

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

Redis单条命令保存原子性,事务不保证原子性。

7.2 Redis的事务

1.开启事务(multi)

127.0.0.1:6379> multi 								# 开启事务OK

2.命令入队 (写命令)

# 命令入队127.0.0.1:6379> set name dazui QUEUED127.0.0.1:6379> set age 18QUEUED

3.执行事务 (exec)

127.0.0.1:6379> exec								# 执行1) OK

正常执行事务!

127.0.0.1:6379> multi 								# 开启事务OK127.0.0.1:6379> set name dazui						# 命令入队QUEUED127.0.0.1:6379> exec								# 执行事务1) OK

放弃事务

127.0.0.1:6379> multi								# 开启事务OK127.0.0.1:6379> set k1 a							# 命令入列QUEUED127.0.0.1:6379> set k2 a							# 命令入列QUEUED127.0.0.1:6379> DISCARD								# 放弃事务OK127.0.0.1:6379> get k1								# 获取String数据(nil)

编译型异常

代码有问题或者命令有错误

​ 如果触发了事务中所有命令都不会执行

127.0.0.1:6379> multi								# 创建事务OK127.0.0.1:6379> set a1 aQUEUED127.0.0.1:6379> set a2 aQUEUED127.0.0.1:6379> set a3 aQUEUED127.0.0.1:6379> getset a1							# 错误命令入列(error) ERR wrong number of arguments for 'getset' command127.0.0.1:6379> set a4 4QUEUED127.0.0.1:6379> exec								# 执行事务,报错(error) EXECABORT Transaction discarded because of previous errors.127.0.0.1:6379> get a1								# 证明了所有的命令都没有被执行(nil)

运行时异常

​ 比如1/0报错,如果事务队列中存在余发星,那么执行命令的时候其他命令都是可以正常执行的,错误命令抛出异常

127.0.0.1:6379> multi								# 创建事务OK127.0.0.1:6379> set k1 "v1"							# 设置值 加入命令队列QUEUED127.0.0.1:6379> incr k1								# 对k1进行自加1,但是k1存放的的数据不是纯数字,就会报错	加入队列QUEUED127.0.0.1:6379> set k2 12							# 设置值 加入队列QUEUED127.0.0.1:6379> exec								# 执行事务1) OK2) (error) ERR value is not an integer or out of range3) OK127.0.0.1:6379> get k2								# 获取k2数据 证明运行时异常其他命令可以正常执行。"12"

8.加锁

8.1 悲观锁

​ 悲观锁认为什么时候都会出问题,无论做什么都会加锁。这样做特别影响性能。

8.2 乐观锁

​ 他认为什么时候都不会出现问题。更新数据的时候去判断下,在此期间是否有人修改过这个数据。

8.3 监视

正常执行

127.0.0.1:6379> set money 100									# 设置100块钱OK127.0.0.1:6379> set out 0										# 设置花出去的钱OK127.0.0.1:6379> watch money										# 监视OK127.0.0.1:6379> MULTI											# 创建事务OK127.0.0.1:6379> decrby money 20									# 钱自减20QUEUED	127.0.0.1:6379> incrby out 20									# 花出去的钱自增20QUEUED127.0.0.1:6379> exec											# 执行1) (integer) 802) (integer) 20

并发情况

线程A

127.0.0.1:6379> set money 100OK127.0.0.1:6379> set out 0OK127.0.0.1:6379> watch money										# 监视OK127.0.0.1:6379> MULTIOK127.0.0.1:6379> decrby money 20QUEUED127.0.0.1:6379> incrby money 20QUEUED127.0.0.1:6379> exec											# 执行 一定要在线程B执行完再去执行 为什么失败?因为在在执行事务他会比较money跟监视时候的值是否相同,如果相同就可以执行,不相同就执行失败,这时候线程B修改了money的值,所以更新失败(nil)

线程B

127.0.0.1:6379> set money 10000OK

放弃监视 解锁

127.0.0.1:6379> UNWATCH											# 取消加锁OK

9.番外

1.为什么Reids是6379

Alessia Merz 是一位意大利舞女、女演员。 Redis 作者 Antirez 早年看电视节目,觉得 Merz 在节目中的一些话愚蠢可笑,Antirez 喜欢造“梗”用于平时和朋友们交流,于是造了一个词 “MERZ”,形容愚蠢,与 “stupid” 含义相同。

后来 Antirez 重新定义了 “MERZ” ,形容”具有很高的技术价值,包含技艺、耐心和劳动,但仍然保持简单本质“。

到了给 Redis 选择一个数字作为默认端口号时,Antirez 没有多想,把 “MERZ” 在手机键盘上对应的数字 6379 拿来用了。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

哇塞大嘴好帅(DaZuiZui)

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值