一、Nosql概述

为什么要用Nosql

1、单机MySQL

90年代,一个基本的网站访问量一般不会很大,单个数据库完全足够,那个时候更多的去使用静态页面html,服务器根本没有太大压力,这种情况下网站的瓶颈是什么?

(1)数据量如果太大,一个机器就放不下

(2)数据的索引(B+Tree),一个机器内存也放不下

(3)访问量(读写混合),一个服务器承受不了

只要出现以上三种情况,你就必须要晋级。

linux redis添加到服务里_redis

2、Memcached(缓存)+MySQL+垂直拆分(读写分离)

网站80%的情况都是在读,每次都要去查询数据库就很麻烦,所以我们希望减轻数据的压力,我们可以使用缓存来保证效率。

发展过程:优化数据结构和索引->文件缓存(IO)->Memcached(当时最热门的技术)

linux redis添加到服务里_linux redis添加到服务里_02

3、分库分表+水平拆分+MySQL集群

技术和业务在发展的同时,对人的要求也越来越高!

本质:数据库(读、写)

早些年MyISAM:表锁,十分影响效率!高并发下就会出现严重的锁问题

转战Innodb:行锁

慢慢的就开始使用分库分表来解决写的压力!MySQL在那个年代推出了表分区!这个并没有多少公司使用。

MySQL的集群,很好满足了那个年代的所有需求!

linux redis添加到服务里_nosql_03

4、如今最近的年代

2010-2020十年之间,世界已经发生了翻天覆地的变化(定位。也是一种数据,音乐,热榜)

MySQL等关系型数据库就不够用了,数据量很多,变化很快

MySQL有的使用它来存储一些比较大的文件,博客,图片。数据库表很大,效率就低了,如果有一种数据库来专门处理这种数据,MySQL压力就变得十分小(研究如何处理这些问题)大数据IO压力下,表几乎没法更大!

linux redis添加到服务里_Redis_04

用户个人信息,社交网络、地理位置。用户自己产生的数据,用户日志等爆发式增长,这时候我们就需要使用NoSQL数据库的,Nosql可以很好的处理以上的情况。

什么是NoSQL

NoSQL

NoSQL = Not Only SQL

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

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

很多的数据类型用户的个人信息,社交网络,地理位置。这些数据类型的存储不需要一个固定的格式!不需要多月的操作就可以横向扩展的!Map<String,Object>使用键值对来控制!

NoSQL特点

1、方便扩展(数据之间没有关系,很好扩展)

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

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

4、传统RDBMS和NoSQL

传统的RDBMS:
-结构化组织
-SQL
-数据和关系都存在单独的表中 row col
-操作,数据定义语言
-严格的一致性
-基础的事物
NoSQL
-不仅仅是数据
-没有固定的查询语言
-键值对存储、列存储、文档存储、图形数据库(社交关系)
-最终一致性
-CAP定理和BASE(异地多活)初级架构师
-高性能、高可用、高可扩

了解:3V+3高

大数据时代的3v:主要是描述问题(1、海量Volume 2、多样Variety 3、实时Velocity)

大数据时代的3高:主要是对程序的要求(1、高并发 2、高可拓 3、高性能)

阿里巴巴演进分析

1、商品的基本信息

名称、价格、商家信息;

关系型数据库就可以解决了!MySQL/Oracle

淘宝内部的MySQL不是大家用的MySQL

2、商品的描述、评论(文字比较多)

文档型数据库中,MongDB

3、图片

分布式文件系统FastDFS

淘宝自己的TFS

Gooale的DFS

Hadoop  HDFS

阿里云的 OSS

4、商品的关键字(搜索)

搜索引擎 solr elasticsearch

ISerach:多隆(技术员)

5、商品热门的波段信息

内存数据库

Redis  Tair、Memache...

6、商品的交易、外部的交易接口

三方应用

大型互联网应用问题:

数据类型太多了、数据源繁多,经常重构、数据改造,大面积改造?

linux redis添加到服务里_redis_05

linux redis添加到服务里_redis_06

 

linux redis添加到服务里_nosql_07

linux redis添加到服务里_linux redis添加到服务里_08

NoSQL的四大分类

KV键值对:

新浪:Redis

美团:Redis+Tair

阿里、百度:Redis+memecache

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

MongoDB(一般必须要掌握)

MongoDB是一个基于分布式文件存储的数据库,c++编写,主要用来处理大量的文件!

MongoDB是一个介于关系型数据库和菲关系型数据库中中间的产品!MongoDB是非关系型数据库中功能最丰富的,最像关系型数据库的!

列存储数据库

HBase(在大数据中出现)

分布式文件系统

图关系数据库

linux redis添加到服务里_Redis_09

它不是存图形,放的是关系,比如:朋友圈社交网络,广告推荐!

Neo4j、InfoGrid;

linux redis添加到服务里_Redis_10

二、Redis入门

概述

Redis是什么

是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、Key-Value数据库,并提供多种语言的API。免费和开源!是当下最热门的NoSQL技术之一!也被人们称之为结构化数据!

Redis能干嘛?

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

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

3、发布订阅系统

4、地图信息分析

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

6、。。。

特性

1、多样的数据类型

2、持久化

3、集群

4、事物

学习中需要用到的东风西

1、官网:Redis

2、中文网:redis中文官方网站

3、下载地址:通过官网下载即可

注意:redis适合在linux上开发。

Windows安装

1、在官网下载redis压缩包(5M左右)

2、双击redis-server开启redis(端口号6379)

3、使用redis客户端来连接redis

4、

linux redis添加到服务里_nosql_11

Linux安装

1、打开官网Redis

linux redis添加到服务里_nosql_12

2、用xftp下载到Linux中

 

linux redis添加到服务里_linux redis添加到服务里_13

 3、解压Redis的安装包,把压缩包移动到opt

linux redis添加到服务里_linux redis添加到服务里_14

 4、进入解压后的文件,可以看到我们redis的配置文件

linux redis添加到服务里_redis_15

5、基本的环境安装

 yum install gcc-c++

gcc -v查看环境

make

安装完毕

linux redis添加到服务里_nosql_16

 再次make

linux redis添加到服务里_Redis_17

 make install

linux redis添加到服务里_Redis_18

 6、查看默认的安装路径 /usr/local/bin

linux redis添加到服务里_nosql_19

 7、将redis的配置文件复制到当前目录下

linux redis添加到服务里_linux_20

 8、redis默认不是后台启动的,修改配置文件

linux redis添加到服务里_Redis_21

9、启动redis服务! 

linux redis添加到服务里_linux_22

10、 开启客户端,使用redis-cli进行连接测试

linux redis添加到服务里_linux_23

linux redis添加到服务里_Redis_24

 11、查看redis的进程是否开启!

linux redis添加到服务里_Redis_25

 12、如何关闭redis服务呢?shutdown

linux redis添加到服务里_linux_26

linux redis添加到服务里_redis_27

或者

./redis-cli shutdown 

 13、再次查看进程是否存在

linux redis添加到服务里_redis_28

14、修改配置文件实现在任何位置都可以启动redis

export JAVA_HOME=/usr/java/jdk1.8.0_301-amd64
export REDIS_HOME=/usr/local/bin
export PATH=$REDIS_HOME/src:$JAVA_HOME/bin:$PATH

 15、后面使用单机多Redis启动集群测试!

测试性能

redis-benchmark是一个压力测试工具!

官方自带的性能测试工具

linux redis添加到服务里_linux_29

 redis-benchmark命令参数!

linux redis添加到服务里_linux redis添加到服务里_30

linux redis添加到服务里_Redis_31

 简单测试:

测试:100个并发连接 100000请求
redis-benchmark -h localhost -p 6379 -c 100 -n 100000

 进行分析:

linux redis添加到服务里_linux redis添加到服务里_32

基础知识

redis默认有16个数据库

linux redis添加到服务里_nosql_33

 默认使用的是第0个

可以使用select进行切换数据库

127.0.0.1:6379> select 3    #切换数据库
OK
127.0.0.1:6379[3]> dbsize   #查看数据库大小
(integer) 0
127.0.0.1:6379[3]> set name qinjiang   #设置key value
OK
127.0.0.1:6379[3]> dbsize
(integer) 1
127.0.0.1:6379> select 7
OK
127.0.0.1:6379[7]> dbsize
(integer) 0
127.0.0.1:6379[7]> get name
(nil)
127.0.0.1:6379[7]> select 3
OK
127.0.0.1:6379[3]> get name  #get值
"qinjiang"
127.0.0.1:6379[3]> keys *    #查看所有的value
1) "name"

清楚当前数据库 flushdb

清楚全部数据库的内容 flushall

127.0.0.1:6379[3]> flushdb
OK
127.0.0.1:6379[3]> keys *
(empty array)

Redis是单线程的!

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

Redis是C语言写的,官方提供的数据为100000+的QPS,完全不比同样是使用key-value 的Memecache差!

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

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

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

速度:CPU>内存>硬盘

核心:redis是将所有的数据全部存放在内存中,所以说使用单线程去操作效率就是最高的,多线程(会出现CPU上下文切换),对于内存系统来说,如果没有上下文切换就是效率最高的!多次读写都是在一个CPU上的,在内存情况下,这就是最佳方案!

五大数据类型

官网文档  Redis

Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件. 它支持多种类型的数据结构,如 字符串(strings), 散列(hashes), 列表(lists), 集合(sets), 有序集合(sorted sets) 与范围查询, bitmaps, hyperloglogs 和 地理空间(geospatial) 索引半径查询. Redis 内置了 复制(replication), LUA脚本(Lua scripting), LRU驱动事件(LRU eviction), 事务(transactions) 和不同级别的 磁盘持久化(persistence), 并通过 Redis哨兵(Sentinel) 和自动 分区(Cluster)提供高可用性(high availability). 

现在将的命令记住,后面使用SpringBoot、Jedis所有的方法就是这些命令!

单点登录可以把一些数据放到Redis里面

Redis-Key

127.0.0.1:6379[3]> keys *
(empty array)
127.0.0.1:6379[3]> set name xingxing
OK
127.0.0.1:6379[3]> get name
"xingxing"
127.0.0.1:6379[3]> set age 18
OK
127.0.0.1:6379[3]> keys *
1) "age"
2) "name"
127.0.0.1:6379[3]> exists name        #name是否存在,1存在,0不存在
(integer) 1
127.0.0.1:6379[3]> exists name1
(integer) 0
127.0.0.1:6379[3]> move name1 1       #move移除key,后面的1代表当前数据库
(integer) 0
127.0.0.1:6379[3]> move name
(error) ERR wrong number of arguments for 'move' command
127.0.0.1:6379[3]> move name 1
(integer) 1
127.0.0.1:6379[3]> kys *
(error) ERR unknown command `kys`, with args beginning with: `*`, 
127.0.0.1:6379[3]> keys *
1) "age"
127.0.0.1:6379[3]> expire age 10      #在几秒后移除age
(integer) 1
127.0.0.1:6379[3]> ttl age            #查看当前秒数
(integer) 5
127.0.0.1:6379[3]> type name          #查看key类型
string
127.0.0.1:6379[3]> type age
string

后面如果遇到不会的命令,可以在官网查看帮助文档。

linux redis添加到服务里_Redis_34

String

127.0.0.1:6379[3]> flushdb                #清空当前数据库
OK
127.0.0.1:6379[3]> set name xingxing      #设置值
OK
127.0.0.1:6379[3]> exists name
(integer) 1
127.0.0.1:6379[3]> append name nihao      #追加字符串,如果当前key不存在,就相当于setkey
(integer) 13
127.0.0.1:6379[3]> get name
"xingxingnihao"
127.0.0.1:6379[3]> strlen name            #获取字符串的长度
(integer) 13
# 增加减少
127.0.0.1:6379[3]> set views 0
OK
127.0.0.1:6379[3]> get views
"0"
127.0.0.1:6379[3]> incr views         #增加1
(integer) 1
127.0.0.1:6379[3]> incr views
(integer) 2
127.0.0.1:6379[3]> get views
"2"
127.0.0.1:6379[3]> decr views         #减掉1
(integer) 1
127.0.0.1:6379[3]> decr views
(integer) 0
127.0.0.1:6379[3]> decr views
(integer) -1
127.0.0.1:6379[3]> get views
"-1"
127.0.0.1:6379[3]> incrby views 5     #增加5
(integer) 4
127.0.0.1:6379[3]> incrby views 5
(integer) 9
127.0.0.1:6379[3]> decrby views 5     #减去5
(integer) 4
127.0.0.1:6379[3]> decrby views 5
(integer) -1
#字符串范围 range
127.0.0.1:6379[3]> get name
"xingxingnihao"
127.0.0.1:6379[3]> getrange name 0 3        #截取[0,3]
"xing"
127.0.0.1:6379[3]> getrange name 0 -1       #截取所有
"xingxingnihao"
127.0.0.1:6379[3]> setrange name 8 hello    #替换指定位置的字符串
(integer) 13
127.0.0.1:6379[3]> get name
"xingxinghello"
# setex(set with expire)    #设置过期时间
# setnx(set if not exist)   #不存在则设置(在分布式锁中会常常使用)

127.0.0.1:6379[3]> set name xinxin
OK
127.0.0.1:6379[3]> setex name 60 hello      #设置name的值为hello,在60s后过期删除掉name
OK
127.0.0.1:6379[3]> ttl name
(integer) 56
127.0.0.1:6379[3]> get name
"hello"
127.0.0.1:6379[3]> setnx myname redis       #如果mykey不存在,则创建mykey
(integer) 1
127.0.0.1:6379[3]> keys *
1) "myname"
2) "name"
3) "views"
127.0.0.1:6379[3]> ttl name
(integer) 13
127.0.0.1:6379[3]> get myname
"redis"
127.0.0.1:6379[3]> setnx myname he          #如果mykey存在,则创建失败!
(integer) 0
127.0.0.1:6379[3]> get myname
"redis"
mset mget
127.0.0.1:6379[3]> mset k1 v1 k2 v2 k3 v3      # 同时设置多个值
OK
127.0.0.1:6379[3]> keys *
3) "k3"
4) "k1"
5) "k2"
127.0.0.1:6379[3]> mget k1 k2 k3               # 同时获取多个值
1) "v1"
2) "v2"
3) "v3"
127.0.0.1:6379[3]> msetnx k1 v1 k4 v4          # msetnx是一个原子性操作,要么一起成功要么一起失败当所有 key 都成功设置,返回 1 。 如果所有给定 key 都设置失败(至少有一个 key 已经存在),那么返回 0 。
(integer) 0
127.0.0.1:6379[3]> keys *
3) "k3"
4) "k1"
5) "k2"
127.0.0.1:6379[3]> get v4
(nil)
# 对象
set user:1 {name:zhangsan,age:3} # 设置一个user:1 对象值为json字符来保存一个对象!

# 这里的key是一个巧妙的设计: user:{id}:{filed},如此设计在Redis中是完全ok的

127.0.0.1:6379[3]> mset user:1:name zhangsan user:1:age 2
OK
127.0.0.1:6379[3]> mget user:1:name user:1:age
1) "zhangsan"
2) "2"
getset # 先get后set
127.0.0.1:6381> getset k2 v2
(nil)
127.0.0.1:6381> get k2
"v2"
127.0.0.1:6381> getset k2 h2
"v2"
127.0.0.1:6381> get k2
"h2"

数据结构是相同的!

String类似的使用场景:value除了是我们的字符串还可以是我们的数字!

计数器

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

List(列表)

在redis里面,我们可以把list完成,栈、队列、阻塞队列!

所有的list命令都是l开头的,Redis不区分大小写命令

lpush 左边插入 rpush 右边插入

lpush 左边插入 rpush 右边插入
127.0.0.1:6379> lpush list a b c d       # 将一个值或者多个值,插入到列表头部(左)
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
127.0.0.1:6379> rpush list -a -b         # 将一个值或者多个值,插入到列表尾部(右)
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "d"
2) "c"
3) "b"
4) "a"
5) "-a"
6) "-b"

lpop 左边移除  rpop右边移除

127.0.0.1:6379> lpop list 2
1) "d"
2) "c"
127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "a"
3) "-a"
4) "-b"
127.0.0.1:6379> rpop list 2
1) "-b"
2) "-a"
127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "a"

lindex 通过下标获取list中的某个值

127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "a"
127.0.0.1:6379> lindex list 1
"a"
127.0.0.1:6379> lindex list 0
"b"

llen 获取列表长度

127.0.0.1:6379> llen list
(integer) 2

lrem 移除指定的值

127.0.0.1:6379> lrange list 0 -1
1) "b"
2) "b"
3) "a"
127.0.0.1:6379> lrem list 3 b
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "a"

ltrim 修剪:list截断

127.0.0.1:6379> rpush list one two
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "two"
127.0.0.1:6379> rpush list three four
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "two"
3) "three"
4) "four"
127.0.0.1:6379> ltrim list 1 2            # 通过下标截取指定的长度,这个list被改变了,只剩下截取的元素
OK
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "three"

rpoplpush   移除列表的最后一个元素,将他移动到新的列表中

127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> rpoplpush list newlist
"three"
127.0.0.1:6379> lrange list 0 -1
1) "one"
2) "two"
127.0.0.1:6379> lrange newlist 0 -1
1) "three"

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 value
(integer) 1
127.0.0.1:6379> lrange list 0 0
1) "value"
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 list hello world
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "world"
127.0.0.1:6379> linsert list before hello first
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "first"
2) "hello"
3) "world"
127.0.0.1:6379> linsert list after hello java
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "first"
2) "hello"
3) "java"
4) "world"

小结

  • 实际上是一个链表
  • 如果key不存在,创建新的链表
  • 如果key存在,新增内容
  • 如果移除了所有值,空链表,也代表不存在
  • 在两边插入或者改动值,效率最高!中间元素,相对效率低

Set(集合)

set中的值不能重复!set是无序不重复集合!

sadd 设置set集合的值        smembers 查看set的所有值        sismember 判断值是否在set中

127.0.0.1:6379> sadd set "hello"            # set集合中添加匀速
(integer) 1
127.0.0.1:6379> sadd set kuangshen
(integer) 1
127.0.0.1:6379> sadd set good
(integer) 1
127.0.0.1:6379> smembers set                # 查看指定set的所有值
1) "kuangshen"
2) "hello"
3) "good"
127.0.0.1:6379> exists set                  # 判断是否存在key
(integer) 1
127.0.0.1:6379> sismember set hello         # 判断某一个值是不是在set集合中
(integer) 1
127.0.0.1:6379> sismember set hi
(integer) 0

scard key 获取key的值

127.0.0.1:6379> scard set
(integer) 3

srem key value 移除key中的value

127.0.0.1:6379> smembers set
1) "kuangshen"
2) "hello"
3) "good"
127.0.0.1:6379> srem set kuangshen
(integer) 1
127.0.0.1:6379> smembers set
1) "hello"
2) "good"

srandmember 随机抽取key中的一个value

127.0.0.1:6379> SRANDMEMBER set      # 随机抽取set中的一个元素
"good"
127.0.0.1:6379> SRANDMEMBER set 2
1) "hello"
2) "good"

spop 随机删除集合中的元素

127.0.0.1:6379> SMEMBERS set
1) "hello"
2) "good"
127.0.0.1:6379> SPOP set 
"hello"

smove 将指定的值从一个集合移动到另一个集合

127.0.0.1:6379> SMEMBERS set
1) "java"
2) "world"
3) "hello"
4) "good"
127.0.0.1:6379> SMEMBERS newset
1) "hi"
127.0.0.1:6379> SMOVE set newset java            # 指定一个值,移动到另一个set集合
(integer) 1
127.0.0.1:6379> SMEMBERS set
1) "world"
2) "hello"
3) "good"
127.0.0.1:6379> SMEMBERS newset
1) "java"
2) "hi"

差集 sdiff        交集 sinter        并集sunion

127.0.0.1:6379> SDIFF set1 set2        # 差集
1) "a"
2) "c"
127.0.0.1:6379> sinter set1 set2       # 交集
1) "b"
127.0.0.1:6379> sunion set1 set2       # 并集
1) "d"
2) "a"
3) "c"
4) "b"
127.0.0.1:6379> SMEMBERS set1
1) "c"
2) "a"
3) "b"
127.0.0.1:6379> SMEMBERS set2
1) "d"
2) "b"

Hash(哈希)

Map集合,keyMap集合

hset hget hmset hmget

127.0.0.1:6379> hset myhash field1 a             # 设置一个字段值
(integer) 1
127.0.0.1:6379> hget myhash field1
"a"
127.0.0.1:6379> hmset myhash field1 b field2 c   # 设置多个字段值
(integer) 1
127.0.0.1:6379> hget myhash field1 
"b"
127.0.0.1:6379> hget myhash field2
"c"
127.0.0.1:6379> hmget myhash field1 field2       # 获取多个字段值
1) "b"
2) "c"
127.0.0.1:6379> hgetall myhash                   # 获取全部的数据
1) "field1"
2) "b"
3) "field2"
4) "c"
127.0.0.1:6379> hdel myhash field1               # 删除hash指定的key字段
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "c"

hlen 获取长度

127.0.0.1:6379> hgetall myhash
1) "field2"
2) "c"
3) "field1"
4) "a"
127.0.0.1:6379> hlen myhash
(integer) 2

hexists 判断hash中的指定字段是否存在

127.0.0.1:6379> HEXISTS myhash field1
(integer) 1

获取所有field,获取所有value

127.0.0.1:6379> hkeys myhash
1) "field2"
2) "field1"
127.0.0.1:6379> HVALS myhash
1) "c"
2) "a"

hincrby 自增

127.0.0.1:6379> hset myhash field3 2
(integer) 1
127.0.0.1:6379> HINCRBY myhash field3 2        # 增加2
(integer) 4
127.0.0.1:6379> HINCRBY myhash field3 -2       # 减少2
(integer) 2
127.0.0.1:6379> HSETNX myhash field4 hello     # field4不存在则创建
(integer) 1
127.0.0.1:6379> HSETNX myhash field4 hi        # field4存在则失败
(integer) 0

hash变更的数据user name age,尤其是用户信息之类,经常变动的信息!hash更适合对象的存储,String更适合字符串存储!

Zset(有序集合)

zset k1 score1 v1

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"

zrangebyscore

127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf            # 从小到大排序
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> ZREVRANGE myset 0 -1                     # 从大到小排序
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf withscores  #显示全部的用户从小到大
1) "one"
2) "1"
3) "two"
4) "2"
5) "three"
6) "3"
127.0.0.1:6379> ZRANGEBYSCORE myset -inf +inf withscores
1) "newone"
2) "1"
3) "one"
4) "1"
5) "two"
6) "2"
7) "three"
8) "3"

移除rem中的元素

127.0.0.1:6379> zrem myset newone
(integer) 1
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
3) "three"
127.0.0.1:6379> zcard myset                # 获取有序集合的个数
(integer) 3

获取指定区间的数量

127.0.0.1:6379> ZCOUNT myset 1 2
(integer) 2

案例思路:set排序 存储班级成绩表,工资表排序!

普通消息,1,重要消息,2,带权重进行判断

排行榜应用实现,取Top N测试!