Redis是什么?
$ Redis(remote didction server)远程字典服务
$是一个开源的使用ansl C语言编写的、支持网络可基于内存亦可持久化的日志型、key-value数据库,并提供了多种语言的APi
$redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记入文件,并且在此基础上实现了master-slave(主从同步)
$免费开源的! 是当今最热门的NOsql技术之一被人称为结构化数据库
$Redis推荐都是在Linux服务器上搭建的,我们是基于Linux学习
Redis的作用?
$内存存储、持久化、内存中断电即失、所以说持久化很重要(rdb、aof)
$效率高、可以用于高速缓存
$发布订阅系统
$地图信息分析
$计时器、计数器(浏览量)
Redis的特性
$多样的数据类型
$持久化
$支持集群
$支持事务
Redis的安装
windows安装:
1下载安装包:https://github.com/microsoftarchive/redis/releases/tag/win-3.2.100
2下载完毕后得到压缩包Redis.x64-3.2.100.zip
3解压到自己的电脑上的环境目录就可以了
4开启redis,双击运行即可
5使用redis客户端来连接redis,服务器不要关 输入ping 输出pong连接成功
window下使用确实简单,但redis推荐我们在linux去开发使用
基础知识
$redis默认有16个数据库
$redis默认使用的是第0个数据库
$可以使用select进行切换数据库
$keys *可以查看数据库中的所有的键值
$flushall清空全部库
$flushdb清空当前库
$DBSIZE查看DB大小
$EXISTS 查找指定字段
$move 移除字段
$EXPIRE 设置过期时间段
$ttl 查看剩余的时间
Redis是单线程的
$明白Redbis是很快的,官方表示redis是基于内存操作,cpu不是redis性能瓶颈,redis的瓶颈是根据机器的内存和网络带宽。可以使用单线程来是实现
$redis是C语言的写的,官方提供的数据为10000+的QPS,完全不比同样使用key-value的memecache差
Redis为什么是单线程还这么快?
$误区1:高性能的服务器一定是多线程的?
$误区2:多线程(cpu上下文会切换)一定比单线程效率高
$核心:redis是将所有的数据全部放在内存中的,所以说使用单线程去操作效率是最高的,对于内存系统来说,如果没有上下文切换效率是最高的
五大数据类型
redis-key
Redis是一种开放源代码(BSD许可)的内存中数据结构存储,用作数据库,缓存和消息代理。它支持数据结构,例如字符串,哈希,列表,集合,带范围查询的排序集合,位图,超级日志,带有半径查询和流的地理空间索引。Redis具有内置的复制,Lua脚本,LRU逐出,事务和不同级别的磁盘持久性,并通过Redis Sentinel和Redis Cluster自动分区提供了高可用性
String(字符串)
127.0.0.1:6379> ping $ 测试是否连接成功
PONG
127.0.0.1:6379> FULSHALL $清空数据库
(error) ERR unknown command 'FULSHALL'
127.0.0.1:6379> set key1 v1 $设置值
OK
127.0.0.1:6379> get key1 $获取值
"v1"
127.0.0.1:6379> keys * $查看数据库
1) "key1"
127.0.0.1:6379> EXISTS key1 $判断某一个key是否存在
(integer) 1
127.0.0.1:6379> APPEND key1 "hello" $往key中添加字段
(integer) 7
127.0.0.1:6379> get key1
"v1hello"
127.0.0.1:6379> STRLEN key1
(integer) 7
127.0.0.1:6379> APPEND key1 ",miao"
(integer) 12
127.0.0.1:6379> get key1
"v1hello,miao"
127.0.0.1:6379>
======================================================================
步长
127.0.0.1:6379> set vs 0 $初始浏览量为0
OK
127.0.0.1:6379> get vs
"0"
127.0.0.1:6379> incr vs $浏览量自增+1
(integer) 1
127.0.0.1:6379> incr vs
(integer) 2
127.0.0.1:6379> decr vs $浏览量自-1
(integer) 1
127.0.0.1:6379> decr vs
(integer) 0
127.0.0.1:6379> decr vs
(integer) -1
127.0.0.1:6379> get vs
"-1"
127.0.0.1:6379> INCRBY vs 100 $浏览量自增1 可以设置步长
(integer) 99
127.0.0.1:6379> DECRBY vs 88 $浏览量自-1 可以设置步长
(integer) 11
==========================================================================================
字符串范围GETRANGE
127.0.0.1:6379> set key1 "hello,javamiao" #设置key1的值
OK
127.0.0.1:6379> get key1
"hello,javamiao"
127.0.0.1:6379> GETRANGE key1 0 3 #截取字符串
"hell"
127.0.0.1:6379>
=========================================================================================
字符串范围SETRANGE (替换)
127.0.0.1:6379> set key2 abcdefg
OK
127.0.0.1:6379> get key2
"abcdefg"
127.0.0.1:6379> SETRANGE key2 1 xx #替换指定位置开始的字符串
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
127.0.0.1:6379>
================================================================================
setex(sex whith expire)#设置过期时间
setnx(set if not exist)#不存在在设置(在分布式中会用到)
127.0.0.1:6379> setex key3 30 "hello" #设置key3的值为hello,30秒后过期
OK
127.0.0.1:6379> ttl key3
(integer) 23
127.0.0.1:6379> get key3
"hello"
127.0.0.1:6379> setnx mykey "redis" #如果mykey不存在,创建mykey
(integer) 1
127.0.0.1:6379> keys *
1) "key1"
2) "mykey"
3) "key2"
127.0.0.1:6379> ttl key3
(integer) -2
127.0.0.1:6379> setnx mykey "mongoDB" #如果mykey存在,创建失败
(integer) 0
127.0.0.1:6379> get mykey
"redis"
==============================================================================
mset
mget
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3 # 同时设置多个值
OK
127.0.0.1:6379> keys *
1) "mykey"
2) "k1"
3) "key2"
4) "k3"
5) "key1"
6) "k2"
127.0.0.1:6379> mget k1 k2 k3 #同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379> msetnx k1 v1 k4 v4 #msetnx 是一个原子性的操作,要么一起成功要么一起失败!
(integer) 0
127.0.0.1:6379> get k4
(nil)
127.0.0.1:6379>
==================================================================================
对象
set user:1{name:zhangsan,age:3} #设置一个user:!对象 值为json字符来保存一个对象
127.0.0.1:6379> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
==================================================================================
LIst
Lpush
Rpush
#在redis里面,我们可以把list玩成栈、队列、阻塞队列!、
#所有的list命令都是用L开头的 ,redis不区分大小写
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 #获取list中的值
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 five 将一个值或多个值,插入列表未部
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "five"
==================================================================================
LPOP
RPOP
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
3) "one"
4) "five"
127.0.0.1:6379> LPOP list #移除list 的第一个元素
"three"
127.0.0.1:6379> Rpop list #移除list 的最后一个元素
"five"
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
==================================================================================
Lindex
127.0.0.1:6379> LRANGE list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> Lindex list 1 #通过下标获得list中的某一个值
"one"
==============================================================================
Llen
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> LLen list #返回列表的长度
(integer) 3
127.0.0.1:6379>
===================================================================
移除指定的值
127.0.0.1:6379> Lpush list three
(integer) 4
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "three"
3) "two"
4) "one"
127.0.0.1:6379> lrem list one #移除list集合中指定的value ,精确匹配
(error) ERR wrong number of arguments for 'lrem' command
127.0.0.1:6379> lrem list 1 one
(integer) 1
127.0.0.1:6379> lrem list 1 three
(integer) 1
127.0.0.1:6379> LRANGE list 0 -1
1) "three"
2) "two"
===================================================================
trim 修剪
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpush mylist "hello3"
(integer) 4
127.0.0.1:6379> ltrim mylist 1 2 #通过下标截取指定的长度,这个list已经被改变了,只剩下截取的元素了
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
=================================================================== ==========
rpoplpush(移除列表的最后一个元素,将他移动到新的列表中)
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "hello1"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpoplpush mylist myotherlist #移除列表中的最后一个元素,将他移动到新的列表中
"hello2"
127.0.0.1:6379> lrange mylist 0 -1 #查看原来的列表
1) "hello"
2) "hello1"
127.0.0.1:6379> lrange myotherlist 0 -1 #查看目标中的列表,确认值是否存在
1) "hello2"
127.0.0.1:6379>
=================================================================== =======
lset(将列表中指定下标的值替换为另一个值,更新操作)
127.0.0.1:6379> exists list #判断列表是否存在
(integer) 0
127.0.0.1:6379> lset list 0 item #如果不存在我们去更新会报错
(error) ERR no such key
127.0.0.1:6379> lpush list value1
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value1"
127.0.0.1:6379> lset list 0 item #如果存在更新当前下标值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> lset list 1 other
(error) ERR index out of range
=================================================================== =======
Linsert #将某个具体的value插入到列表中的某个元素的前面或者后面
127.0.0.1:6379> rpush mylist "hello"
(integer) 1
127.0.0.1:6379> rpush mylist "world"
(integer) 2
127.0.0.1:6379> linsert mylist befote "world" "other"
(error) ERR syntax error
127.0.0.1:6379> linsert mylist before "world" "other"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
127.0.0.1:6379> linsert mylist after world new
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello"
2) "other"
3) "world"
4) "new"
=================================================================== =======
set(集合)
set中的值不能重复读的
127.0.0.1:6379> sadd myset "hello" #set中添加元素
(integer) 1
127.0.0.1:6379> sadd myset "miao"
(integer) 1
127.0.0.1:6379> sadd myset "lovemiao"
(integer) 1
127.0.0.1:6379> smembers myset #查看指定set的值
1) "lovemiao"
2) "hello"
3) "miao"
127.0.0.1:6379> sismember myset hello #判断某个值是否存在存在反回1
(integer) 1
127.0.0.1:6379> sismember myset word #不存在反回0
(integer) 0
127.0.0.1:6379> scard myset #获取set中内容的个数
(integer) 3
127.0.0.1:6379> srem myset hello #移除set中的指定元素
(integer) 1
127.0.0.1:6379> smembers myset
1) "lovemiao"
2) "miao"
127.0.0.1:6379> sadd myset "hello"(integer)
1127.0.0.1:6379>sadd myset "miao"(integer)
1127.0.0.1:6379> sadd myset "lovemiao"(integer)
1127.0.0.1:6379> smembers myset1) "lovemiao"2) "hello"3) "miao"
127.0.0.1:6379> sismember myset hello(integer)
1127.0.0.1:6379> sismember myset word(integer) 0
=================================================================== =======
hash(哈希)
MAp集合,key-map
这个值是一个map集合! 本质上和string'类型没有太大区别,还是一个简单的key-value
hash可以用来做一些变更数据
127.0.0.1:6379> hset myhash field1 kuangshen #set一个具体的key-vlaue
(integer) 1
127.0.0.1:6379> hget myhash field1 #获取一个字段值
"kuangshen"
127.0.0.1:6379> hmset myhash field1 hello field2 word #set多个 key-value
OK
127.0.0.1:6379> hmget myhash field1 field2 #获取多个字段值
1) "hello"
2) "word"
127.0.0.1:6379> hgetall myhash #获取全部数据
1) "field1"
2) "hello"
3) "field2"
4) "word"
127.0.0.1:6379> hdel myhash field1 #删去hash指定的字段对应的value值也就销毁
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "word"
127.0.0.1:6379> hlen myhash #获取hash表的字段长度
(integer) 1
127.0.0.1:6379>
127.0.0.1:6379> hkeys myhash #只获取key的值
1) "field2"
127.0.0.1:6379> hvals myhash #只获取value的值
1) "word"
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 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 5000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 500 miao
(integer) 1
127.0.0.1:6379> zrangebyscore salary -inf +inf #显示所有的用户 从小到大
1) "miao"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379>
127.0.0.1:6379> zrangebyscore salary -inf +inf withscores #显示所有用户并且附带成绩
1) "miao"
2) "500"
3) "xiaohong"
4) "2500"
5) "zhangsan"
6) "5000"
127.0.0.1:6379> zrangebyscore salary -inf 2500 withscores #显示工资小于2500员工的升序排序
1) "miao"
2) "500"
3) "xiaohong"
4) "2500"
================================================================== =======
rem移除元素
127.0.0.1:6379> zrange salary 0 -1
1) "miao"
2) "xiaohong"
3) "zhangsan"
127.0.0.1:6379> zrem salary xiaohong
(integer) 1
127.0.0.1:6379> zrange salary 0 -1
1) "miao"
2) "zhangsan"
================================================================== =======
127.0.0.1:6379> zadd myzset 1 hello
(integer) 1
127.0.0.1:6379> zadd myzset 2 world 3 kuangshen
(integer) 2
127.0.0.1:6379> zcount myzset 1 3 #获取指定区间的成员变量
(integer) 3
127.0.0.1:6379> zcount myzset 1 2
(integer) 2
================================================================== ========================================================================= =======
三大特殊数据类型
geospatial(地理位置)
GEOADD 将制定的地理空间位置(维度 经度 名称)添加到绑定的key中
GEODIST
GEOHASH
GEOPOS
GEORADIUS
GEORADIUSBYMEMBER
=====================================================================================================
GEOADD添加地理位置
#规则:两级无法直接添加我们一般会下载城市数据,直接通过java程序一次性导入
#参数: key 值(维度 经度 名称)
#有效的经度从-180度到180度
#有效的维度从-85.05112878度到80.05112878度
127.0.0.1:6379> geoadd china:city 116.40 39.90 beijing
(integer) 1
127.0.0.1:6379> geoadd china:city 121.47 31.23 shanghai
(integer) 1
127.0.0.1:6379> geoadd china:city 106.50 29.53 chongqi 114.05 22.52 shengzheng
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
=====================================================================================================
GEOPOS命令
#(从key里返回所有给定位置元素的位置(精度和纬度))
#获得当前位置的地理位置 一定是一个坐标值
127.0.0.1:6379> geopos china:city beijing #获取指定的城市的经度和维度
1) 1) "116.39999896287918"
2) "39.900000091670925"
127.0.0.1:6379> geopos china:city chongqi
1) 1) "106.49999767541885"
2) "29.529999579006592"
=====================================================================================================
GEODIS命令
#返回两个给定位置之间的距离
#两人之间的距离
#单位:
m单位为米
km 单位为千米
mi单位为英里
ft单位为英尺
127.0.0.1:6379> geodist china:city beijing shanghai km #北京到上海的距离 单位km
"1067.3788"
(1.70s)
127.0.0.1:6379> geodist china:city beijing chongqi km #北京到重庆的距离
"1464.0708"
================================================================================
georadius(获取地理位置)
#以给定的经纬度为中心,找出某一半径的元素
#我附近的人?(获得所有附近的人的地址,定位) 通过半径来查询
#所有的数据都应该融入到china:city中
127.0.0.1:6379> georadius china:city 110 30 1000 km #以100 30 这个经纬度为中心 。寻找方圆1000km内的城市
1) "chongqi"
2) "xian"
3) "shengzheng"
4) "hangzhou"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist #显示到中心距离的位置
1) 1) "chongqi"
2) "341.9374"
2) 1) "xian"
2) "483.8340"
127.0.0.1:6379> georadius china:city 110 30 500 km withcoord #显示出城市的经纬度或者是显示周围人的定位信息
1) 1) "chongqi"
2) 1) "106.49999767541885"
2) "29.529999579006592"
2) 1) "xian"
2) 1) "108.96000176668167"
2) "34.2599996441893"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 1 #筛选指定的结果
1) 1) "chongqi"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
127.0.0.1:6379> georadius china:city 110 30 500 km withdist withcoord count 2
1) 1) "chongqi"
2) "341.9374"
3) 1) "106.49999767541885"
2) "29.529999579006592"
2) 1) "xian"
2) "483.8340"
3) 1) "108.96000176668167"
2) "34.2599996441893"
===========================================================================
georadiusbymember(指定位置)
#找出位于指定元素周围的其他元素
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"
===========================================================================
geohash命令
#该命令返回11个字符的geohash字符串
#将二维的经纬度转换为一位的字符串,如果两个字符串越接近,那么距离就越近
127.0.0.1:6379> geohash china:city beijing chongqi
1) "wx4fbxxfke0"
2) "wm5xzrybty0"
===========================================================================
GEO
#geo底层的实现原理其实就是zset 我们可以使用zset命令来操作geo
127.0.0.1:6379> zrange china:city 0 -1 #查看地图中全部元素
1) "chongqi"
2) "xian"
3) "shengzheng"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city beijing #移除指定元素
(integer) 1
===========================================================================
HYperloglog 数据结构(消除冗余)
#不重复的元素
#hyperloglog基数统计算法
#优点:占用内存是固定的,只需要12kb内存
#网页uv(一个人访问一个网站多次,但是还算作一个人)
127.0.0.1:6379> pfadd mykey a b c d e f g h i g k· #创建第一组元素 mykey
(integer) 1
127.0.0.1:6379> pfcount mykey
(integer) 10
127.0.0.1:6379> pfadd mykey2 k a b v c o p l h g m #创建第二组元素 mykey2
(integer) 1
127.0.0.1:6379> pfcount mykey2
(integer) 11
127.0.0.1:6379> pfmerge mykey3 mykey mykey2 合并第一组和第二组的元素 并重名为mykey3
OK
127.0.0.1:6379> pfcount mykey3
(integer) 15
bitmaps(二进制)
#位储存
#统计用户信息 ,(活跃,不活跃%登入,未登入%在线,下线%打卡,未打卡)两个状态都可以使用bitmaps
#bitmaps位图,数据结构 都是操作二进制记录,就只有0和1两个状态
127.0.0.1:6379> setbit sign 0 1 #使用bitmaps来记录周一到周日的打卡
(integer) 0
127.0.0.1:6379> setbit sign 1 0
(integer) 0
127.0.0.1:6379> setbit sign 2 1
(integer) 0
127.0.0.1:6379> setbit sign 3 0
(integer) 0
127.0.0.1:6379> setbit sign 4 1
(integer) 0
127.0.0.1:6379> setbit sign 5 0
(integer) 0
127.0.0.1:6379> setbit sign 6 1
(integer) 0
127.0.0.1:6379> getbit sign 3 #查看某一天是否打卡
(integer) 0
127.0.0.1:6379> getbit sign 6 #查看某一天是否打卡
(integer) 1
127.0.0.1:6379> bitcount sign #统计这周的打卡记录
(integer) 4
================================================================
redis(事务)
#事务的本质:一组命令的集合,一个事务的所有命令都会被序列化,在事务执行过程中,会按照顺序执行
#一次性,顺序性执行一些的命令
#redis单条命令是保存原子性的,但是事务是不保存原子性的
#redis的事务:
开启事务(multi)
命令入队(输入命令)
执行事务(exec)
127.0.0.1:6379> multi #开启事务
OK
#命令入队,顺序执行
127.0.0.1:6379> set k1 v2
QUEUED
127.0.0.1:6379> set k2 v2
QUEUED
127.0.0.1:6379> get k2
QUEUED
127.0.0.1:6379> set k3 v3
QUEUED
127.0.0.1:6379> exec #执行事务
1) OK
2) OK
3) "v2"
4) OK
============================================
放弃事务
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 k4 v4
QUEUED
127.0.0.1:6379> discard #discard取消事务
OK
127.0.0.1:6379> get k4 #事务中的命令都不会被执行
(nil)
#编译时异常(代码有问题,命令有错)事务中所有的代码都不会被执行
#运行时异常 如果事务队列中存在语法性,那么执行命令的时候,其他命令时可以正常执行的,错误命令抛出异常
===========================================================
监视watch
悲观锁:很悲观,仍未什么时候都会出现问题,无论做什么都会加锁
乐观锁:很乐观,认为什么时候都不会出现问题,所以不会上锁,
更新数据的时候会去判断一下,在此之间是否有人修改过这个数据
获取version
更新的时候比较version
watch乐观锁
unwatch解锁
127.0.0.1:6379> set monkey 100
OK
(1.64s)
127.0.0.1:6379> set out 0
OK
127.0.0.1:6379> watch monkey #监视monkey对象
OK
127.0.0.1:6379> multi #事务正常结束,数据期间没有发生变动,这个时候就正常执行成功
OK
127.0.0.1:6379> decrby monkey 20
QUEUED
127.0.0.1:6379> incrby out 20
QUEUED
127.0.0.1:6379> exec
1) (integer) 80
浙公网安备 33010602011771号