您现在的位置是:首页 > 正文

Redis快速入门(基本操作 一)

2024-02-01 05:07:34阅读 2

学Java就到狂神说
Redis简介:
Redis 是一个开源(BSD许可)的,内存中的数据结构存储系统,它可以用作数据库、缓存和消息中间件。

Nosql
泛指非关系型的数据库。随着互联网web2.0网站的兴起,传统的关系数据库在处理web2.0网站,特别是超大规模和高并发的SNS类型的web2.0纯动态网站已经显得力不从心,出现了很多难以克服的问题,而非关系型的数据库则由于其本身的特点得到了非常迅速的发展。NoSQL数据库的产生就是为了解决大规模数据集合多重数据种类带来的挑战,尤其是大数据应用难题
NoSQL特点:
1、数据之间没有关系,容易扩展
2、大数据量高性能
3、数据类型是多样型的!(不需要事先设计数据库!随取随用!如果是数据量十分大的表,很多人就无法设计了)
4、传统的关系型数据库(RDBMS)和NoSQL

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

NoSQL的四大分类

KV键值对:

  • 新浪:Redis
  • 美团:Redis + Tair

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

  • MongoDB(掌握)

    • MongoDB 是一个基于分布式文件存储的数据库,C++编写,用来处理大量文档
    • MongoDB 是一个介于关系型数据库和非关系型数据库中间产品!MongoDB 是非关系型数据库中功能最丰富,最像关系型数据库的!
  • ConthDB

列存储数据库:

  • HBase
  • 分布式文件系统

图关系数据库:

  • 不是放图形的,是放关系的)
  • Neo4j ,InfoGrid

Redis入门

Redis是什么?

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

Redis能干嘛?

1、内存存储、持久化,内存中是断电即失,所以说持久化很重要(rdb 、 aof)
2、效率高,可以用于高速缓存
3、发布订阅系统

特性

1、多样的数据类型
2、持久化
3、集群
4、事务

Linux安装

1 程序放在opt目录下
[root@iz8vb4nxo286g9mk6p8fnhz home]# mv redis-5.0.8.tar.gz /opt
2 然后进入opt目录
[root@iz8vb4nxo286g9mk6p8fnhz opt]# cd /opt
3 解压
[root@iz8vb4nxo286g9mk6p8fnhz opt]# tar -zxvf redis-5.0.8.tar.gz 
4 进入解压后的文件
[root@iz8vb4nxo286g9mk6p8fnhz opt]# cd redis-5.0.8
  • 基本的环境安装
1.进入解压后的文件 , 安装环境
yum install gcc-c++
2.执行make命令,会把所有需要的文件都配置上
make
make install
  • redis的默认安装路径user/local/bin
1.进入bin目录
cd usr/local/bin
2.创建一个文件夹
mkdir myconfig
3.将redis的配置文件拷贝过来
cp /opt/redis-5.0.8/redis.conf myconfig
  • redis默认不是后台启动的,我们要更改配置文件
1 进入刚才放redis的配置的文件夹
cd myconfig
2 进入之后找到下图中的daemonize 后边的no改为yes
vim redis.conf
  • 运行redis
    在/usr/local/bin目录下运行,如下图
    通过指定的配置文件启动服务
    在这里插入图片描述
  • 使用redis-cli进行连接测试
    在这里插入图片描述
  • 查看redis的进程是否开启
    在这里插入图片描述
  • 关闭redis服务
[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-cli -p 6379
127.0.0.1:6379> shutdown
not connected> exit

完毕!

测试性能

redis-benchmark 是一个压力测试工具!
官方自带的性能测试工具
参数如下:在这里插入图片描述

# 记得先连接redis 再测试
# 测试:100个并发连接  100000个请求
[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-benchmark -h localhost -p 6379 -c 100 -n 100000

基础的知识

redis默认有16个数据库
默认使用的是第0个
可以使用select进行切换数据库!

[root@iz8vb4nxo286g9mk6p8fnhz bin]# redis-cli -p 6379
127.0.0.1:6379> select 3
OK
127.0.0.1:6379[3]> DBSIZE #使用dbsize来查看数据
(integer) 0
127.0.0.1:6379[3]> set name qianyi #set设置数据
OK
127.0.0.1:6379[3]> DBSIZE
(integer) 1
127.0.0.1:6379[3]> get name  #get获取数据
"qianyi"
127.0.0.1:6379[3]> keys * #查看所有key
127.0.0.1:6379[3]> flushdb #清空当前数据库 , 也可以flushall清空所有
OK
127.0.0.1:6379[3]> get name
(nil)

Redis是单线程的

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

Redis 是C语言写的

Redis 为什么单线程还这么快?
1、误区1 :高性能的服务器一定是多线程的?
2、误区2 :多线程(CPU上下文会切换!)一定比单线程效率高

核心:redis 是将所有的数据全部放在内存中的,所以说使用单线程去操作效率是最高的。对于内存系统来说,如果没有上下文切换效率是最高的。


五大数据类型

Redis-Key

# 一些简单命令
127.0.0.1:6379> EXISTS name # 判断当前的key是否存在
127.0.0.1:6379> move name 1 # 将key值为name的移动到1号数据库
127.0.0.1:6379> keys *
1) "name"
127.0.0.1:6379> EXPIRE name 10 # 设置name的过期时间为10s
(integer) 1
127.0.0.1:6379> ttl name # 查看name的生命周期
(integer) 7
127.0.0.1:6379> ttl name
(integer) 3
127.0.0.1:6379> get name
(nil)
127.0.0.1:6379> type name # 查看key的类型
string

String(字符串)

########################################################################
127.0.0.1:6379[1]> set key1 v1
OK
127.0.0.1:6379[1]> EXISTS key1
(integer) 1
127.0.0.1:6379[1]> get key1
"v1"
127.0.0.1:6379[1]> APPEND key1 "hello"  # 在key1后边追加字符串
(integer) 7
127.0.0.1:6379[1]> get key1
"v1hello"
127.0.0.1:6379[1]> APPEND key1 ",qianyi"
(integer) 14
127.0.0.1:6379[1]> STRLEN key1 # 查看key1的长度,和java中的用法差不多 strlen
(integer) 14
127.0.0.1:6379[1]> get key1
"v1hello,qianyi"
########################################################################
# i++ i+=
127.0.0.1:6379[1]> set views 0 # 初始浏览量0
OK
127.0.0.1:6379[1]> get views
"0"
127.0.0.1:6379[1]> incr views  # 自增1命令 incr
(integer) 1
127.0.0.1:6379[1]> incr views
(integer) 2
127.0.0.1:6379[1]> get views
"2"
127.0.0.1:6379[1]> decr views  # 自减1命令 decr
(integer) 1
127.0.0.1:6379[1]> get views
"1"
127.0.0.1:6379[1]> incrby views 10  # incrby 指定增量10
(integer) 11
127.0.0.1:6379[1]> get views
"11"
127.0.0.1:6379[1]> decrby views 3   # decrby 指定减量10
(integer) 8
127.0.0.1:6379[1]> get views
"8"
########################################################################
# 获取字符串  指定范围  range
127.0.0.1:6379> set key1 "hello,qianyi"
OK
127.0.0.1:6379> get key1
"hello,qianyi"
127.0.0.1:6379> getrange key1 0 3    # 获取下标从0-3的字符串
"hell"
127.0.0.1:6379> getrange key1 0 -1   # 0 -1 代表获取全部
"hello,qianyi"
########################################################################
#替换 字符串!! 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   # setrange 指定字符串 下标 要替换的内容
(integer) 7
127.0.0.1:6379> get key2
"axxdefg"
########################################################################
# setex : 设置过期时间
# setnx : 不存在 则 设置
127.0.0.1:6379> setex key3 30 "my time has 30 seconds"  # 过期时间 30s
OK
127.0.0.1:6379> ttl key3
(integer) 24
127.0.0.1:6379> get key3
"my time has 30 seconds"
127.0.0.1:6379> setnx mykey "the first value"  # 第一次设置不存在mykey
(integer) 1
127.0.0.1:6379> get mykey
"the first value"
127.0.0.1:6379> setnx mykey "the second value" # 第二次设置,已经存在mykey
(integer) 0				       # 所以返回0 , 设置失败
127.0.0.1:6379> get mykey
"the first value"
########################################################################
# mset : 批量设置值
# mget : 批量获取值
# msetnx : 若不存在则设置
127.0.0.1:6379> mset k1 v1 k2 v2 k3 v3  # 批量设置
OK
127.0.0.1:6379> keys *
1) "k3"
2) "k1"
3) "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)
########################################################################
# user:1:name  用户1的姓名 
# user:1:age   用户1的年龄
127.0.0.1:6379> mset user:1:name qianyi user:1:age 15 
OK
127.0.0.1:6379> mget user:1:name user:1:age
1) "qianyi"
2) "15"
127.0.0.1:6379> mset user:2:name zhangsan user:2:age 13
OK
127.0.0.1:6379> mget user:1:name user:1:age user:2:name user:2:age
1) "qianyi"
2) "15"
3) "zhangsan"
4) "13"
########################################################################
# getset 先获取再设置
127.0.0.1:6379> getset name abcde  # 如果不存在值,则返回nil
(nil)
127.0.0.1:6379> get name
"abcde"
127.0.0.1:6379> getset name 123456 # 如果存在值,获取原来的值,并设置新的值
"abcde"
127.0.0.1:6379> get name
"123456"
########################################################################

列表(list)

在redis里面,我们可以把list玩成栈、队列、阻塞队列!
所有的list命令都是用l开头的

######e################################################################
# 操作list的基本命令
# lpush :将一个或多个值插入到队列头部   rpush : 将一个或多个值插入到队列尾部
# lpop : 弹出队列头部的一个元素        rpop  : 弹出队列尾部的一个元素
# lrange : 查看  
# lindex : 获取对应下标的值
127.0.0.1:6379> keys *
(empty list or set)
127.0.0.1:6379> lpush list one two three
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "two"
3) "one"
127.0.0.1:6379> lpop list
"three"
127.0.0.1:6379> rpush list four
(integer) 3
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"d
3) "four"

######################################################################
# lindex
127.0.0.1:6379> lrange list 0 -1
1) "two"
2) "one"
127.0.0.1:6379> lindex list 1
"one"
127.0.0.1:6379> lindex list 0
"two"

######################################################################
#  llen : 查看list长度
127.0.0.1:6379> lpush list one two three four five
(integer) 5
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> llen list
(integer) 5
######################################################################
#  lrem : 移除指定的值
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "three"
4) "two"
5) "one"
127.0.0.1:6379> lpush list three
(integer) 6
127.0.0.1:6379> lrange list 0 -1
1) "three"
2) "five"
3) "four"
4) "three"
5) "two"
6) "one"
127.0.0.1:6379> lrem list 2 three   #   移除两个three (2 代表count 数量)
(integer) 2
127.0.0.1:6379> lrange list 0 -1
1) "five"
2) "four"
3) "two"
4) "one"

######################################################################
#  ltrim : 根据下标来截断list,同时返回截断的值,同时list被改变。
127.0.0.1:6379> lpush mylist "hello1"
(integer) 1
127.0.0.1:6379> lpush mylist "hello2"
(integer) 2
127.0.0.1:6379> lpush mylist "hello3"
(integer) 3
127.0.0.1:6379> lpush mylist "hello4"
(integer) 4
127.0.0.1:6379> lrange mylist 0 -1
1) "hello4"
2) "hello3"
3) "hello2"
4) "hello1"
127.0.0.1:6379> ltrim mylist 1 2   # 截断mylist从1-2的值
OK
127.0.0.1:6379> lrange mylist 0 -1
1) "hello3"
2) "hello2"

######################################################################
#  rpoplpush : 移除指定列表的最后一个元素到另一个列表的头部
127.0.0.1:6379> rpush mylist "hello1"
(integer) 1
127.0.0.1:6379> rpush mylist "hello2"
(integer) 2
127.0.0.1:6379> rpush mylist "hello2"
(integer) 3
127.0.0.1:6379> rpop mylist
"hello2"
127.0.0.1:6379> rpush mylist "hello3"
(integer) 3
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
3) "hello3"
127.0.0.1:6379> rpoplpush mylist myotherlist   #  rpoplpush : 移除指定列表的最后一个元素到另一个列表的头部
"hello3"
127.0.0.1:6379> lrange mylist 0 -1
1) "hello1"
2) "hello2"
127.0.0.1:6379> lrange myotherlist 0 -1
1) "hello3"
######################################################################
#  lset : 将列表中指定下标的值改为另一个值
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  #  lset : 将列表中指定下标的值改为另一个值
OK
127.0.0.1:6379> lrange list 0 0
1) "item"
127.0.0.1:6379> exists list
(integer) 1
######################################################################
#  linsert : 在指定值的前边或后边插入值
127.0.0.1:6379> rpush list hello
(integer) 1
127.0.0.1:6379> rpush list world
(integer) 2
127.0.0.1:6379> linsert list before world before
(integer) 3
127.0.0.1:6379> linsert list after world after
(integer) 4
127.0.0.1:6379> lrange list 0 -1
1) "hello"
2) "before"
3) "world"
4) "after"

Set(集合)

set中的值不能重复

######################################################################
#  sadd : 往myset 里边添加元素
#  smembers : 查看myset 中的元素
#  sismember : 查看某值是否存在myset 中,存在 返回1 ; 不存在 返回0
#  scard  : 获取set集合中元素的个数
127.0.0.1:6379> sadd myset hello
(integer) 1
127.0.0.1:6379> sadd myset qianyi
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
3) "hello"
127.0.0.1:6379> sismember myset qianyi
(integer) 1
127.0.0.1:6379> scard myset
(integer) 3
######################################################################
#  srem : 移除指定的值
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
3) "hello"
127.0.0.1:6379> srem myset hello
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "qianyi"
######################################################################
# set : 无序不重复集合
# srandmember : 随机抽取指定个数元素
127.0.0.1:6379> sadd myset one two three four five six seven eight nine ten
(integer) 10
127.0.0.1:6379> smembers myset
 1) "two"
 2) "one"
 3) "four"
 4) "six"
 5) "seven"
 6) "five"
 7) "eight"
 8) "ten"
 9) "three"
10) "nine"
127.0.0.1:6379> srandmember myset
"nine"
127.0.0.1:6379> srandmember myset
"ten"
127.0.0.1:6379> srandmember myset 2
1) "nine"
2) "four"
######################################################################
# spop : 随机弹出指定的值
127.0.0.1:6379> spop myset
"nine"
127.0.0.1:6379> spop myset
"eight"
127.0.0.1:6379> spop myset
"ten"
127.0.0.1:6379> spop myset
"one"
127.0.0.1:6379> spop myset
"three"
127.0.0.1:6379> spop myset
"five"
127.0.0.1:6379> smembers myset
1) "four"
2) "six"
3) "seven"
4) "two"
######################################################################
#  smove : 将指定的元素移动到另一个集合中
127.0.0.1:6379> sadd myset "hello"
(integer) 1
127.0.0.1:6379> sadd myset world
(integer) 1
127.0.0.1:6379> sadd myset qianyi
(integer) 1
127.0.0.1:6379> smove myset myset2 qianyi
(integer) 1
127.0.0.1:6379> smembers myset
1) "world"
2) "hello"
127.0.0.1:6379> smembers myset2
1) "qianyi"
######################################################################
 B站的共同关注。
# sdiff : 求两个集合的差集
# sinter : 求两个集合的交集
# sunion : 求两个集合的并集
127.0.0.1:6379> clear
127.0.0.1:6379> sadd myset1 a b c
(integer) 3
127.0.0.1:6379> sadd myset2 c d e
(integer) 3
127.0.0.1:6379> smembers myset1
1) "c"
2) "b"
3) "a"
127.0.0.1:6379> smembers myset2
1) "c"
2) "d"
3) "e"
127.0.0.1:6379> smembers myset1 myset2
(error) ERR wrong number of arguments for 'smembers' command
127.0.0.1:6379> sdiff myset1 myset2
1) "b"
2) "a"
127.0.0.1:6379> sinter myset1 myset2
1) "c"
127.0.0.1:6379> sunion myset1 myset2
1) "c"
2) "d"
3) "b"
4) "a"
5) "e"

Hash(哈希)

Map集合 , key - map ! 这个值是一个map

#################################################
# hset : 添加值
# hget : 获取值
# hmset : 一次添加多个值  hmget : 一次获取多个值
# hgetall : 获取hash中的所有值
# hdel : 删除hash里的某个值
# hlen : 查看hash中的map的个数
127.0.0.1:6379> hset myhash field1 qianyi
(integer) 1
127.0.0.1:6379> hget myhash field1
"qianyi"
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hmget myhash field1 field2
1) "hello"
2) "world"
127.0.0.1:6379> hgetall myhash
1) "field1"
2) "hello"
3) "field2"
4) "world"
127.0.0.1:6379> hdel myhash field1
(integer) 1
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
127.0.0.1:6379> hlen myhash
(integer) 1
#################################################
# hkeys : 获得所有的field
# hvals : 获得所有的value
127.0.0.1:6379> hmset myhash field1 hello field2 world
OK
127.0.0.1:6379> hgetall myhash
1) "field2"
2) "world"
3) "field1"
4) "hello"
127.0.0.1:6379> hkeys myhash
1) "field2"
2) "field1"
127.0.0.1:6379> hvals myhash
1) "world"
2) "hello"
#################################################
# hincrby 指定增量
# hsetnx 不存在则设置
127.0.0.1:6379> hset myhash field3 1
(integer) 1
127.0.0.1:6379> hincrby myhash field3 5
(integer) 6
127.0.0.1:6379> hsetnx myhash field3 1
(integer) 0
127.0.0.1:6379> hsetnx myhash field4 1
(integer) 1

Zset(有序集合)

在set的基础上增加了一个值 , set k1 v1 zset k1 score1 v1(根据score排序)

# zadd : 添加   
127.0.0.1:6379> zadd myset 1 one
(integer) 1
127.0.0.1:6379> zadd myset 2 two
(integer) 1
127.0.0.1:6379> zrange myset 0 -1
1) "one"
2) "two"
######################################################################
# 可自己定义排序
# srangebyscore
127.0.0.1:6379> zadd salary 2500 xiaohong
(integer) 1
127.0.0.1:6379> zadd salary 1000 zhangsan
(integer) 1
127.0.0.1:6379> zadd salary 500 qianyi
(integer) 1
127.0.0.1:6379> ZREVRANGE salary 0 -1 withscores  # 从大到小排序
1) "xiaohong"
2) "2500"
3) "zhangsan"
4) "1000"
5) "qianyi"
6) "500"

.1:6379> zrangebyscore salary -inf +inf withscores #-inf :负无穷 +inf:正无穷 从小到大排序
1) "qianyi"
2) "500"
3) "zhangsan"
4) "1000"
5) "xiaohong"
6) "2500"
127.0.0.1:6379> zrangebyscore salary -inf 1000 withscores  # 只要负无穷-1000的
1) "qianyi"
2) "500"
3) "zhangsan"
4) "1000"

三种特殊数据类型

geospatial 地理位置

朋友的定位 附近的人 打车距离计算。

可以查询一些测试数据: 城市经度纬度查询 (百度)

只有6个命令:
在这里插入图片描述

##################################################
# geoadd : 添加地理位置
# 规则 : 北极南极无法直接添加,我们一般会下载城市数据,直接通过java程序一次性导入。
# 参数:  key   值(纬度,经度,名称)
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 chongqing 114.05 22.52 shenzhen
(integer) 2
127.0.0.1:6379> geoadd china:city 120.16 30.24 hangzhou
(integer) 1
127.0.0.1:6379> geoadd china:city 108.96 34.26 xian
(integer) 1
###################################################
# geodist : 查询两地之间的距离  后边可以添加单位
# m 表示单位为米。
# km 表示单位为千米。
# mi 表示单位为英里。
# ft 表示单位为英尺
# geopos : 查询某地的经纬度
# georadius : 查询指定经纬度附近指定距离的地区
# georadiusbymember : 查询指定地区附近指定距离的地区
# 用于 : 附近的人。
127.0.0.1:6379> geodist china:city beijing chongqing
"1464070.8051"
127.0.0.1:6379> geodist china:city beijing chongqing km
"1464.0708"
127.0.0.1:6379> geopos china:city chongqing
1) 1) "106.49999767541885376"
   2) "29.52999957900659211"
127.0.0.1:6379> georadius china:city 110 50 1000 km
(empty list or set)
127.0.0.1:6379> georadius china:city 110 50 10000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> georadius china:city 110 50 5000 km
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> georadius china:city 110 50 2000 km
1) "xian"
2) "beijing"
127.0.0.1:6379> georadiusbymember china:city chongqing 200 km
1) "chongqing"
127.0.0.1:6379> georadiusbymember china:city chongqing 500 km
1) "chongqing"
127.0.0.1:6379> georadiusbymember china:city chongqing 1000 km
1) "chongqing"
2) "xian"
#################################################
# zrange : 查看所有城市
# zrem : 移除指定元素
127.0.0.1:6379> zrange china:city 0 -1
1) "chongqing"
2) "xian"
3) "shenzhen"
4) "hangzhou"
5) "shanghai"
6) "beijing"
127.0.0.1:6379> zrem china:city chongqing
(integer) 1
127.0.0.1:6379> zrange china:city 0 -1
1) "xian"
2) "shenzhen"
3) "hangzhou"
4) "shanghai"
5) "beijing"

Hyperloglog

Hyperloglog:
是基数统计的算法!
优点:占用的内存是固定的,只需要 12KB的内存,如果从内存的角度来说的话,Hyperloglog是首选的!

网页的 UV (一个人访问一个网站多次,但是还是算作一个人)
传统的方式 , set 保存用户的id,然后统计set的元素个数即可。
但是这个方式如果保存大量的用户ID,就会比较麻烦!我们的目的是为了计数 ,而不是保存ID。

测试使用

# PFADD  : 添加元素
# PFCOUNT : 统计有多少个元素
# PFMERGE : 合并两个key , 并生成新的key
# 统计不重复的 ! ! !
127.0.0.1:6379> PFADD mykey1 a b c d e f g h i j k l 
(integer) 1
127.0.0.1:6379> PFCOUNT mykey1
(integer) 12
127.0.0.1:6379> PFADD mykey2 i j k l m n 
(integer) 1
127.0.0.1:6379> PFCOUNT mykey2
(integer) 6
127.0.0.1:6379> PFMERGE mykey3 mykey1 mykey2
OK
127.0.0.1:6379> PFCOUNT mykey3
(integer) 14

如果允许容错,那么一定可以使用 Hyperloglog
如果不允许容错,就是用set或者自己的数据类型即可!

Bitmap

位存储

统计疫情感染人数 : 0 1 0 1 0 0 0 1
统计用户信息 : 活跃,不活跃!登录 ,未登录!打卡,365打卡!
两个状态的都可以使用 Bitmaps,位图!
操作二进制位来进行记录,就只有 0 和 1 两个状态!

使用btimap 来记录周一到周日的打卡!
周一 : 1 周二 : 1 周三 : 0 …

127.0.0.1:6379> setbit sign 0 1
(integer) 0
127.0.0.1:6379> setbit sign 1 1
(integer) 0
127.0.0.1:6379> setbit sign 2 0
(integer) 0
127.0.0.1:6379> setbit sign 3 1
(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 0
(integer) 0

查看某一天是否打卡

127.0.0.1:6379> getbit sign 6
(integer) 0
127.0.0.1:6379> getbit sign 1
(integer) 1

统计打卡的天数

127.0.0.1:6379> bitcount sign
(integer) 4

网站文章

  • 华为工程师终于把困扰我多年的「操作系统和计算机网络」讲明白了

    华为工程师终于把困扰我多年的「操作系统和计算机网络」讲明白了

    计算机网络、计算机操作系统这两个“兄弟”是所有开发岗位都需要“结拜”的,不管你是 Java、C++还是测试。对于后端开发的童鞋来说,计算机网络的重要性不亚于语言基础,毕竟平时开发经常会和网络打交道,比如:抓个包等等。所以对这一块知识点的准备还是要抱着敬畏之心,不要放过任何一个漏网之题。

    2024-02-01 05:07:26
  • 跟着小刘一起入门一下Sharding jdbc

    跟着小刘一起入门一下Sharding jdbc

    文章目录sharding jdbc -缘起分库分表的出现小结分库分表带来问题Sharding JDBC 介绍快速入门 sharding jdbc -缘起 前段时间,在工作接手了一个新的项目,我问Bos...

    2024-02-01 05:07:18
  • SQL数据库

    SQL数据库

    SQL简介

    2024-02-01 05:06:48
  • Spring AOP 中的两种动态代理

    Spring AOP 中的两种动态代理

    Spring AOP 主要用到的 动态代理,在spring aop的实现中,采用了两种方式,一种是基于接口的动态代理,另外一种是基于类的动态代理。在谈动态代理前,先谈下设计模式中的代理模式:代理模式:为另一对象提供一个替身或占位符以控制对这个对象的访问。类图如下:1,基于接口的动态代理必须首先要定义接口:代码如下:package co...

    2024-02-01 05:06:41
  • NotNull、NotBlank、NotEmpty的使用

    NotNull:校验对象不为nullNotBlank:校验字符串是否为null、或者空字符串,去除空格NotEmpty:校验集合是否为null、或者长度是否为0

    2024-02-01 05:06:33
  • access数据类型转换

    Access数据类型转换  (2012-02-09 20:51:31)转载▼标签: 杂谈分类: 数据库每个函数都可以将表达式 (表达式:算术或逻辑运算符、常数、函数和字段名称、控件和属性的任意组合,计算结果为单个值。表达式可执行计算、操作字符或测试数据。)强制转换为特定的数据类型 (数据类型:决定字段可拥有的数据类型的字段特征。数据类

    2024-02-01 05:06:03
  • 初中计算机授课教案模板,初中课程教案模板

    第二课哭泣的自然《环境被破环》说课教案一、教材的地位与作用《环境被破坏》是教科版八年级下册第一单元第二课第二部分的内容。本单元主要对学生进行环境科学教育,贯穿着“正确认识自然和人类的关系”这一思想。整...

    2024-02-01 05:05:57
  • 总结Windbg常用命令

    1.symfix命令自动将符号路径设置来指向Microsoft 符号存储。系统强制把Microsoft 符号存储的路径覆盖了原有的路径,那么,要使用追加,请使用.symfix+,把原有的路径设回去再保存,再调用.symfix+.2..cls用于清屏3. reload4. lastevent 输出最后一个调试事件所在的进程、线程等简单信息//断点相关

    2024-02-01 05:05:49
  • Java实现word、excel、ppt转pdf文件,pdf转图片(无水印)

    Java实现word、excel、ppt转pdf文件,pdf转图片(无水印)

    在网上也是找了好久才找到的一些比较好的资料,我自己总结梳理了一下,方便后面各位小伙伴使用。 1、效果图 所需的架包百度网盘: 百度网盘连接http:// https://pan.baidu.com/s...

    2024-02-01 05:05:20
  • SQL:从入门到“精通”

    SQL:从入门到“精通”

    SQL:从入门到“精通”

    2024-02-01 05:05:13