政务公开网站建设工作情况汇报,网站播放器源码,全球搜官网,酷特智能服装定制常用中间件Redis详解
一、Redis概述
1.2、NoSQL
1、什么是NoSQL Not Only SQL #xff1a;不仅仅是sql#xff0c;泛指非关系型数据库 。 NoSQL不依赖于业务逻辑方式存储#xff0c;而以简单的key—value 模式存储。大大增加了扩展能力
2、NoSQL特点
方便扩展#x…常用中间件Redis详解
一、Redis概述
1.2、NoSQL
1、什么是NoSQL Not Only SQL 不仅仅是sql泛指非关系型数据库 。 NoSQL不依赖于业务逻辑方式存储而以简单的key—value 模式存储。大大增加了扩展能力
2、NoSQL特点
方便扩展数据之间没有关系很好扩展大数据量高性能Redis 一秒写八万次读取11万次NoSQL的缓存记录级是一种细粒度的缓存性能会比较高数据类型是多样型的不需要事先设计数据库随取随用
1.2、NoSQL的四大分类
KV键值对
新浪Redis美团RedisTair阿里、百度Redis memecache
文档型数据库 bjson和json一样
MongdDB一般必须要掌握 MongdDB是一个基于分布式文件存储的数据库C编写主要用来处理大量的文档MongdDB是一个介于关系型数据库和非关系型数据库中间的产品MongdDB是非关系型数据库中功能最丰富、最像关系型数据库的 ConthDB
列存储数据库 :
HBase分布式文件系统
图关系数据库
不是存图形的放的是关系比如朋友圈社交网络广告推荐Neo4jInfoGrid
1.3、Redis概述
Redis是什么
RedisRemote Dictionary Server 即远程服务字典
是一个开源的使用ANSI C语言编写、支持网络、可基于内存亦可持久化的日志型、key-value数据库并提供多种语言的API。
Redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录文件并且在此基础上实现了master-slave主从同步。
Redis能干什么
内存存储、持久化内存中是断电即失、所以说持久化很重要rdb、aof效率高可以用于高速缓存发布订阅系统地图信息分析计时器、计数器浏览量…
Redis特性
多样的数据类型持久化集群事务
1.4、安装 Linux下安装 1、去官网下载安装包。后缀.tar.gz
2、将压缩包放入到linux文件中
3、解压
tar -zxvf redis-xxxx4、基本的环境安装
yum install gcc-c
make
make install5、默认安装路径/ usr/local/bin
6、复制一份redis.conf到当前目录config下
7、设置配置文件里daemonize yes
8、启动
# 服务端启动
redis-server configs/redis.conf
# 客户端启动
redis-cli -h 主机号 -p 端口号
auth 密码#查看redis启动状态
ps -ef | grep redis二、五大数据类型
Redis是一个开源的内存中的数据结构存储系统它可以用作数据库、缓存和信息中间件MQ。它支持多种类型的数据结构如 字符串散列列表集合有序集合与范围查询和地理空间索引半径查询。Reids内置了复制LUA脚本LRU驱动事件事务和不同级别的磁盘持久化并通过Redis哨兵和自动分区提供高可用性。
2.1、Reids-Key
127.0.0.1:6379 ping #测试连接
PONG
127.0.0.1:6379 FlushALL #清空所有数据库
OK
127.0.0.1:6379 keys * #查看所有key
(empty list or set)
127.0.0.1:6379 set name xqh #新建一个key
OK
127.0.0.1:6379 keys *
1) name
127.0.0.1:6379 set age 1
OK
127.0.0.1:6379 keys *
1) age
2) name
127.0.0.1:6379 EXISTS name #判断当前的key是否存在
(integer) 1
127.0.0.1:6379 move name 1 #移除当前的key
(integer) 1
127.0.0.1:6379 keys *
1) age
127.0.0.1:6379 get age
1
127.0.0.1:6379 EXPIRE age 10 #使这个key十秒后过期单位是秒
(integer) 1
127.0.0.1:6379 ttl age #查看当前key的剩余时间
(integer) -2
127.0.0.1:6379 get age
(nil)
127.0.0.1:6379 keys *
1) age
2) name
127.0.0.1:6379 type name #查看当前key的类型
string
127.0.0.1:6379 type age
string2.2、String字符串
127.0.0.1:6379 set key1 v1 #设置值
OK
127.0.0.1:6379 keys * #查看所有key
1) key1
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 ,xqh
(integer) 11
127.0.0.1:6379 STRLEN KEY1
(integer) 0
127.0.0.1:6379 STRLEN key1
(integer) 11
127.0.0.1:6379 get key1
v1hello,xqh
127.0.0.1:6379
------------------------------------------------------------------------------------------------
127.0.0.1:6379 set views 0
OK
127.0.0.1:6379 get views
0
127.0.0.1:6379 incr views #自增1 浏览量变为1
(integer) 1
127.0.0.1:6379 incr views
(integer) 2
127.0.0.1:6379 get views #获得当前浏览量
2
127.0.0.1:6379 decr views #自减1 浏览量-1
(integer) 1
127.0.0.1:6379 decr views
(integer) 0
127.0.0.1:6379 get views
0
127.0.0.1:6379 INCRBY views 10 #设置步长指定增量
(integer) 10
127.0.0.1:6379 INCRBY views 10
(integer) 20
127.0.0.1:6379DECRBY views 5
(integer) 15------------------------------------------------------------------------------------------------
127.0.0.1:6379 get key1
hello,xqh
127.0.0.1:6379 GETRANGE key1 0 3 #截取字符串 【0,3】闭区间
hell
127.0.0.1:6379 GETRANGE key1 0 -1 #截取所有字符串和 get key 是一样的
hello,xqh
127.0.0.1:6379 set key2 abcdefg
OK
127.0.0.1:6379 SETRANGE key2 1 xx # 从下标1开始替换为xx
(integer) 7
127.0.0.1:6379 get key2
axxdefg
------------------------------------------------------------------------------------------------
127.0.0.1:6379 setex key3 30 hello #设置过期时间
OK
127.0.0.1:6379 ttl key3
(integer) 24
127.0.0.1:6379 get key3
hello
127.0.0.1:6379 setnx mykey redis #不存在这个key的话才设置这个值在分布锁中会常常使用
(integer) 1 #设置成功
127.0.0.1:6379 keys *
1) key2
2) mykey
3) key1
127.0.0.1:6379 setnx mykey mongdb
(integer) 0 #设置失败因为已经存在mykey
127.0.0.1:6379------------------------------------------------------------------------------------------------127.0.0.1:6379 mset k1 v1 k2 v2 k3 v3 #同时设置多个值
OK
127.0.0.1:6379 keys *
1) k3
2) k2
3) k1
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 #设置失败k1存在k4不存在设置失败说明msetnx是一个原子性操作要么都成功要么都失败不能k1创建失败而k4创建成功
(integer) 0
127.0.0.1:6379 get k4
(nil)
127.0.0.1:6379
------------------------------------------------------------------------------------------------
127.0.0.1:6379 mset user:1:name zhangshan user:1:age 2 #对象作为值
OK
127.0.0.1:6379 mget user:1:name user:1:age
1) zhangshan
2) 2
127.0.0.1:6379------------------------------------------------------------------------------------------------
#getset 先获取再设置。先获取如果不存在就返回nil并创建
127.0.0.1:6379 getset db redis #获取dbdb不存在所以返回nil并创建一个dbredis
(nil)
127.0.0.1:6379 get db
redis
127.0.0.1:6379 getset db mongdb # 获取dbdb存在先获取原来的值再赋新的值覆盖
redis
127.0.0.1:6379 get db
mongdb
127.0.0.1:6379------------------------------------------------------------------------------------------------String类型的使用场景value除了是我们的字符串还可以是我们的数字
计数器统计多单位的数量粉丝数对象缓存存储
2.3、List
基本的数据类型列表。
在redis里面我们可以把list玩成栈、队列、阻塞队列
redis不区分大小写命令
127.0.0.1:6379 ping #测试连接
PONG
127.0.0.1:6379 keys *
(empty list or set)
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
1) three
2) two
3) one
127.0.0.1:6379 LRANGE list 0 1
1) three
2) two127.0.0.1:6379 RPUSH list righr #将一个值或者多个值 插入到列表的尾部
(integer) 4
127.0.0.1:6379 LRANGE list 0 -1
1) three
2) two
3) one
4) righr127.0.0.1:6379 lrange list 0 -1
1) three
2) two
3) one
4) righr
127.0.0.1:6379 lpop list #移除列表list第一个元素
three
127.0.0.1:6379 lrange list 0 -1
1) two
2) one
3) righr
127.0.0.1:6379 rpop list #移除列表list最后一个元素
righr
127.0.0.1:6379 lrange list 0 -1
1) two
2) one127.0.0.1:6379 lindex list 1 #通过下标获取list中某一个值
one127.0.0.1:6379 llen list #获取列表长度
(integer) 2#移除指定元素
127.0.0.1:6379 lrange list 0 -1
1) three
2) two
3) one
4) zero
127.0.0.1:6379 lrem list 1 one #移除列表中1一个one
(integer) 1
127.0.0.1:6379 lrange list 0 -1
1) three
2) two
3) zero
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) zero
127.0.0.1:6379 lrem list 2 three #移除列表中两个three
(integer) 2
127.0.0.1:6379 lrange list 0 -1
1) two
2) zero#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 lrange mylist 0 -1
1) hello
2) hello1
3) hello2
4) hello3
127.0.0.1:6379 ltrim mylist 1 2 #通过下标截取指定长度 只保留下标1到2
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 #移除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 exists list #列表是否存在
(integer) 0
127.0.0.1:6379 lpush list value1
(integer) 1
127.0.0.1:6379 lrange list 0 -1
1) value1
127.0.0.1:6379 lset list 0 item # 将列表中指定下标的值替换为另一个值更新操作。
OK
127.0.0.1:6379 lrange list 0 -1
1) item
127.0.0.1:6379 lset list 1 other #列表不存在下标1所以报错
(error) ERR index out of range#linsert 将某个值插入到列表中某个值的前面或者后面
127.0.0.1:6379 lpush mylist hello
(integer) 1
127.0.0.1:6379 lpush mylist hello1
(integer) 2
127.0.0.1:6379 linsert mylist before hello1 other #在hello1的前面插入other
(integer) 3
127.0.0.1:6379 lrange list 0 -1
(empty list or set)
127.0.0.1:6379 lrange mylist 0 -1
1) other
2) hello1
3) hello
127.0.0.1:6379 linsert mylist after hello1 other #在hello1的后面插入other
(integer) 4
127.0.0.1:6379 lrange mylist 0 -1
1) other
2) hello1
3) other
4) hello
2.4、Set集合
set中的值是不能重复的
127.0.0.1:6379 sadd myset hello #set集合中添加元素
(integer) 1
127.0.0.1:6379 sadd myset xqh
(integer) 1
127.0.0.1:6379 sadd myset love
(integer) 1
127.0.0.1:6379 smembers myset #查看指定set的所有值无序、不重复的集合
1) xqh
2) love
3) hello
127.0.0.1:6379 sismember myset hello #判断一个元素是否在set集合中有---1 没有---0
(integer) 1
127.0.0.1:6379 sismember myset xxx
(integer) 0127.0.0.1:6379 scard myset #获取set中值的个数
(integer) 3127.0.0.1:6379 srem myset hello #移除集合中某一个元素
(integer) 1
127.0.0.1:6379 smembers myset
1) xqh
2) love#随机抽出指定个数的元素
127.0.0.1:6379 smembers myset
1) love
2) hello
3) hello3
4) xqh
5) hello2
6) hello1
127.0.0.1:6379 srandmember myset
hello1
127.0.0.1:6379 srandmember myset
hello3
127.0.0.1:6379 srandmember myset
hello
127.0.0.1:6379 srandmember myset 2
1) hello
2) hello2
127.0.0.1:6379 srandmember myset 2
1) hello1
2) hello2#随机删除
127.0.0.1:6379 smembers myset
1) hello3
2) xqh
3) love
4) hello2
5) hello1
6) hello
127.0.0.1:6379 spop myset #随机删除集合中的一个元素
love
127.0.0.1:6379 smembers myset
1) hello3
2) xqh
3) hello2
4) hello1
5) hello#将一个指定的值移除并且添加到另一个集合中127.0.0.1:6379 sadd myset2 set2
(integer) 1
127.0.0.1:6379 smove myset myset2 xqh
(integer) 1
127.0.0.1:6379 smembers myset2
1) xqh
2) set2#交集并集差集不同
127.0.0.1:6379 sadd key1 a
(integer) 1
127.0.0.1:6379 sadd key1 b
(integer) 1
127.0.0.1:6379 sadd key1 c
(integer) 1
127.0.0.1:6379 sadd key2 c
(integer) 1
127.0.0.1:6379 sadd key2 d
(integer) 1
127.0.0.1:6379 sadd key2 e
(integer) 1
127.0.0.1:6379 smembers key1
1) c
2) a
3) b
127.0.0.1:6379 smembers key2
1) d
2) c
3) e
127.0.0.1:6379 sdiff key1 key2 #差集不同的元素
1) a
2) b
127.0.0.1:6379 sinter key1 key2 #交集 相同的部分 共同的好友可以这样实现
1) c
127.0.0.1:6379 sunion key1 key2 #并集
1) b
2) a
3) d
4) e
5) c2.5、Hash哈希
Map集合key-map集合 key- key-vlaue ,这时候的值是一个map集合。本质和String类型没有太大区别
127.0.0.1:6379 hset myhash field1 xqh #set一个具体的key-value
(integer) 1
127.0.0.1:6379 hget myhash field1 # 取出值
xqh
127.0.0.1:6379 hmset myhash field1 hello field2 world #set多个key-value
OK
127.0.0.1:6379 hmget myhash field1 field2 #取出多个值
1) hello
2) world
127.0.0.1:6379 hgetall myhash #查看所有key-value
1) field1
2) hello
3) field2
4) world127.0.0.1:6379 hdel myhash field1 #删除hash指定key字段对应的value值也消失了
(integer) 1
127.0.0.1:6379 hgetall myhash
1) field2
2) world#获取长度
127.0.0.1:6379 hgetall myhash
1) field2
2) world
3) field1
4) hello
5) field3
6) xqh
7) field
8) xqhx
127.0.0.1:6379 hlen myhash #获取哈希表的字段数量
(integer) 4127.0.0.1:6379 hexists myhash field1 #判断指定字段是否存在
(integer) 1#获取所有的key获取所有的value
127.0.0.1:6379 hkeys myhash
1) field2
2) field1
3) field3
4) field
127.0.0.1:6379 hvals myhash
1) world
2) hello
3) xqh
4) xqhx127.0.0.1:6379 hgetall myhash
1) field1
2) 4
127.0.0.1:6379 hincrby myhash field1 -2 # hincrby自增正是就增加负数就减少
(integer) 2
127.0.0.1:6379 hsetnx myhash field4 hello #如果field4不存在就添加这个元素所以这里添加成功
(integer) 1
127.0.0.1:6379 hsetnx myhash field4 xqh #因为field4已经存在了所以这里添加失败
(integer) 0
hash应用
hash变更数据和string类型类似但是比string更方便。尤其是用户信息的保存还有经常变动的信息。hash更适合对象的存储而string更适合字符串的存储
2.6、Zset有序集合
在set的基础上增加了一个值 zset k1 score1 v1 score1 2 …优先级
127.0.0.1:6379 zadd myset 1 one #添加一个值 中间要加一个数字代表优先级从1到后面排序越后
(integer) 1
127.0.0.1:6379 zadd myset 2 two
(integer) 1
127.0.0.1:6379 zadd myset 3 three 4 four
(integer) 2
127.0.0.1:6379 zrange myset 0 -1
1) one
2) two
3) three
4) four 127.0.0.1:6379 zrange salary 0 -1 #从小到大
1) xiaohong
2) zhangshan
3) xiaolan
127.0.0.1:6379 zrevrange salary 0 -1 #从大到小
1) xiaolan
2) zhangshan
3) xiaohong127.0.0.1:6379 zrange salary 0 -1 withscores #升序排列显示全部的用户并带上成绩值
1) xiaohong
2) 2500
3) zhangshan
4) 5000
5) xiaolan
6) 20000
127.0.0.1:6379 zrevrange salary 0 -1 withscores #降序排列显示全部的用户并带上成绩值
1) xiaolan
2) 20000
3) zhangshan
4) 5000
5) xiaohong
6) 2500127.0.0.1:6379 zrangebyscore salary -inf 10000 withscores #小于10000工资的用户升序排列
1) xiaohong
2) 2500
3) zhangshan
4) 5000127.0.0.1:6379 zrevrangebyscore salary inf 3000 withscores #大于3000工资的降序排列
1) xiaolan
2) 20000
3) zhangshan
4) 5000#删除指定元素
127.0.0.1:6379 zrange salary 0 -1
1) xiaohong
2) zhangshan
3) xiaolan
127.0.0.1:6379 zrem salary xiaohong #删除xiaohong
(integer) 1
127.0.0.1:6379 zrange salary 0 -1
1) zhangshan
2) xiaolan#获取有序集合中的个数
127.0.0.1:6379 zcard salary
(integer) 2#获取指定区间的成员数量
127.0.0.1:6379 zrange salary 0 -1 withscores
1) zhangshan
2) 5000
3) xiaochen
4) 10000
5) xiaolan
6) 20000
127.0.0.1:6379 zcount salary 5000 20000
(integer) 3
这些只是一些常用的api其他的遇到再去查官方文档
三、三种特殊数据类型
3.1、geospatial 地理位置
朋友定位附近的人打车距离计算
Redis的Geo 这个功能可以推算地理位置的信息两地之间的距离等
可以查询一些测试数据
6个命令 ################################################################################################
#geoadd 添加地理位置
#规则两级无法直接添加我们一般会下载城市数据直接通过java程序一次性导入!
#有效的经度从-180度到180度。
#有效的纬度从-85.05112878度到85.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 shenzhen
(integer) 2
127.0.0.1:6379 geoadd china:city 120.16 30.24 hangzhou 108.96 34.26 xian
(integer) 2
################################################################################################
# 获取当前定位一定是一个坐标值
127.0.0.1:6379 geopos china:city beijing #获取指定城市的经度和纬度
1) 1) 116.399998962879180912) 39.90000009167092543
127.0.0.1:6379 geopos china:city beijing shanghai
1) 1) 116.399998962879180912) 39.90000009167092543
2) 1) 121.470001637935638432) 31.22999903975783553
################################################################################################
#两人之间的距离
#单位
#m 表示单位为米。
#km 表示单位为千米。
#mi 表示单位为英里
#ft 表示单位为英尺。
#如果用户没有显式地指定单位参数 那么 GEODIST 默认使用米作为单位。
127.0.0.1:6379 geodist china:city beijing shanghai km #查看上海到北京的直线距离单位km
1067.3788
#################################################################################################
#查找附近的人需要获得所有附近的人的地址定位通过半径来查询
#获取指定数量的人
#前提所有数据应该都录入china:city
127.0.0.1:6379 georadius china:city 110 30 1000 km #以110,30这个经纬度为中心寻找方圆1000km内的城市
1) chongqi
2) xian
3) shenzhen
4) hangzhou
127.0.0.1:6379 georadius china:city 110 30 500 km #以110,30这个经纬度为中心寻找方圆500km内的城市
1) chongqi
2) xian
127.0.0.1:6379 georadius china:city 110 30 500 km withdist #以110,30这个经纬度为中心寻找方圆500km内的城市顺带输出离中心距离110,30的位置
1) 1) chongqi2) 341.9374
2) 1) xian2) 483.8340
127.0.0.1:6379 georadius china:city 110 30 500 km withcoord #以110,30这个经纬度为中心寻找方圆500km内的城市顺带输出他人的定位信息主要是经纬度
1) 1) chongqi2) 1) 106.499997675418853762) 29.52999957900659211
2) 1) xian2) 1) 108.960001766681671142) 34.25999964418929977
127.0.0.1:6379 georadius china:city 110 30 500 km withcoord count 1 #以110,30这个经纬度为中心寻找方圆500km内的城市筛选出指定数量的数据
1) 1) chongqi2) 1) 106.499997675418853762) 29.52999957900659211
################################################################################################
#找出位于指定元素周围的其他元素
127.0.0.1:6379 georadiusbymember china:city beijing 1000 km #查找北京附近1000km的城市
1) beijing
2) xian
#################################################################################################
#geohash该命令将返回11个字符的geohash字符串
#将二维的经纬度转换为一维的字符串如果两个字符串越接近那么则距离越近
127.0.0.1:6379 geohash china:city beijing chongqi
1) wx4fbxxfke0
2) wm5xzrybty0
#################################################################################################
#GEO底层的实现原理其实就是zset我们可以使用zset命令来操作geo
127.0.0.1:6379 zrange china:city 0 -1 #查看地图中全部的元素之前通过geoadd添加进去的
1) chongqi
2) xian
3) shenzhen
4) hangzhou
5) shanghai
6) beijing
127.0.0.1:6379 zrem china:city beijing #移除指定元素
(integer) 1
127.0.0.1:6379 zrange china:city 0 -1
1) chongqi
2) xian
3) shenzhen
4) hangzhou
5) shanghai
4.2、Hyperloglog
基数不重复的元素
A{1,3,5,7,8,7}
B{1,3,5,7,8}
基数不重复的元素 5
简介redis 2.8.9版本就更新了Hyperloglog数据结构
基数统计的算法网页的UV一个人访问一个网站多次但是还是算作一个人
传统的方式set保存用户的id 然后就可以统计set中的元素数量作为标准判断
这个方式如果保存大量的用户id就会比较麻烦我们的目的是为了计数而不是保存用户id
优点 占用的内存是固定2^64 不同的元素的技术只需要费 12kb内存所以如果要从内存角度来比较的话 Hyperloglog 首选
测试使用
127.0.0.1:6379 pfadd mykey a b c d e f g h i j #创建第一组元素
(integer) 1
127.0.0.1:6379 pfcount mykey #统计第一组元素数量
(integer) 10
127.0.0.1:6379 pfadd mykey2 i j k l m n b v
(integer) 1
127.0.0.1:6379 pfcount mykey2
(integer) 8
127.0.0.1:6379 pfmerge mykey3 mykey mykey2 #将第一组和第二组合并到第三组中不能有重复的元素所以一共是15个
OK
127.0.0.1:6379 pfcount mykey3
(integer) 15
允许容错的话可以使用这个Hyperloglog。如果不允许误差就不能用这个。
4.3、Bitmaps
位存储
统计用户信息活跃、不活跃登录、未登录打开等两个状态的都可以使用bitmaps
Bitmaps 位图数据结构 都是操作二进制来进行记录就只有0和1两个状态
测试 #记录周一到周日的打卡情况。下标0-6代表周一至周日0代表未打卡1代表打卡
127.0.0.1:6379 setbit sign 0 1
(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 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 1
(integer) 0#查看某一天是否打卡
127.0.0.1:6379 getbit sign 3
(integer) 1
127.0.0.1:6379 getbit sign 5
(integer) 0#统计打卡天数
127.0.0.1:6379 bitcount sign #统计这周打卡记录
(integer) 5
四、事务
1、Redis事务本质一组命令的集合一个事务中的所有命令都会被序列化在事务执行过程中会按照顺序执行一次性、顺序性、排他性Redis中没有隔离级别的概念。
2、redis的事务
开启事务multi命令入队…执行事务exec
3、正常执行事务
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 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) OK127.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 #取消事务
OK
127.0.0.1:6379 get k4 #事务队列中命令都不会被执行
(nil)编译型异常代码有问题命令有错事务中所有的命令都不会被执行运行时异常1/0 如果事务队列中存在语法性错误那么执行命令的时候其他命令可以正常执行错误命令会抛出异常 #运行时异常
127.0.0.1:6379 multi
OK
127.0.0.1:6379 set k1 v1
QUEUED
127.0.0.1:6379 incr k1 #代码没问题只是用错了这里字符串不能递增
QUEUED
127.0.0.1:6379 set k2 v2
QUEUED
127.0.0.1:6379 set k3 v3
QUEUED
127.0.0.1:6379 get k3
QUEUED
127.0.0.1:6379 exec #执行不报错错误的命令行不能执行而其他命令行继续执行
1) OK
2) (error) ERR value is not an integer or out of range
3) OK
4) OK
5) v3
127.0.0.1:6379 get k2 #其他的命令行成功执行
v24、监控watch
悲观锁当一个线程获得该资源锁时其他任何线程都不能获得。只有等该线程执行完释放锁其他线程才有机会获得锁乐观锁当一个线程获得该资源锁时其他线程也可以获取只是在更新数据的时候去判断一下在此期间是否有人修改过和这个数据CAS/版本号机制
五、Jedis
我们要使用Java来操作Redis
什么是Jedis
是Redis官方推荐的java连接开发工具使用java操作Redis中间件如果你要使用java操作redis那么一定要对jedis十分的熟悉。
测试
导入依赖 dependencies!-- 导入jedis的包 --dependencygroupIdredis.clients/groupIdartifactIdjedis/artifactIdversion4.2.3/version/dependency
!-- fastjson--dependencygroupIdcom.alibaba/groupIdartifactIdfastjson/artifactIdversion2.0.2/version/dependency/dependencies
编码测试
package com.qian;import redis.clients.jedis.Jedis;public class TestPing {public static void main(String[] args) {//1.new Jedis 对象即可Jedis jedis new Jedis(127.0.0.1,6379);//jedis所有的命令就是我们之前学习的所有命令System.out.println(jedis.ping());//测试连接}
}
//输出pong
常用API所有的api和前面的命令一模一样
package com.qian;
import redis.clients.jedis.Jedis;
import java.util.Set;public class TestKey {public static void main(String[] args) {Jedis jedis new Jedis(127.0.0.1,6379);System.out.println(清空数据:jedis.flushDB());System.out.println(判断某个键是否存在jedis.exists(username));System.out.println(新增键值对:jedis.set(username,xqh));System.out.println(新增键值对:jedis.set(password,123456));System.out.println(系统中所有的键如下);SetString keys jedis.keys(*);System.out.println(keys);System.out.println(删除passwordjedis.del(password));System.out.println(判断键password是否存在jedis.exists(password));System.out.println(判断username所存储的值的类型:jedis.type(username));System.out.println(新增键值对:jedis.set(project,chinese));System.out.println(随机返回key空间的一个:jedis.randomKey());System.out.println(重命名keyjedis.rename(username,name));System.out.println(取出改后的name的值jedis.get(name));System.out.println(按索引查询:jedis.select(0));System.out.println(返回当前数据库中key的数目jedis.dbSize());System.out.println(删除当前选择数据库中的所有key:jedis.flushDB());System.out.println(删除所有数据库中的所有key:jedis.flushAll());}
}
...//和之前的命令一模一样需要使用可以直接翻前面的笔记喔通过Jedis再次理解事务
package com.qian;import com.alibaba.fastjson.JSONObject;
import com.google.gson.JsonObject;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.Transaction;public class TestTX {public static void main(String[] args) {Jedis jedis new Jedis(127.0.0.1, 6379);jedis.flushDB();JSONObject jsonObject new JSONObject();jsonObject.put(hello,world);jsonObject.put(name,xqh);//开启事务Transaction multi jedis.multi();String result jsonObject.toJSONString();try {multi.set(user1, result);multi.set(user2, result);int i 1/0; //代码抛出异常事务执行失败multi.exec(); //成功就执行事务}catch (Exception e){multi.discard();//如果失败就放弃事务e.printStackTrace();}finally {System.out.println(jedis.get(user1));System.out.println(jedis.get(user2));jedis.close(); //关闭连接}}
}
//代码错误事务执行失败get不到输出null六、SpringBoot集成Redis
SpringBoot操作数据
整合测试
导入依赖 !-- 操作redis--dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency
配置连接 redis:# 地址host: 192.168.180.100# 端口默认为6379port: 6379# 密码password: 123456# 连接超时时间timeout: 10slettuce:pool:# 连接池中的最小空闲连接min-idle: 0# 连接池中的最大空闲连接max-idle: 5# 连接池的最大数据库连接数max-active: 5# #连接池最大阻塞等待时间使用负值表示没有限制max-wait: -1msdatabase: 6测试
package com.example;import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.core.RedisTemplate;SpringBootTest
class Redis02SpringbootApplicationTests {Autowiredprivate RedisTemplate redisTemplate;Testvoid contextLoads() {redisTemplate.opsForValue().set(mukey,xqh);System.out.println(redisTemplate.opsForValue().get(mukey));}}
redisTemplate.opsForValue().set(“mukey”,“xqh”);
传递对象要序列化
package com.example.pojo;import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;import java.io.Serializable;Component
AllArgsConstructor
NoArgsConstructor
Data
//在企业中我们的所有pojo都会序列化
public class User implements Serializable {private String name;private int age;
}
//test
Testpublic void test() throws JsonProcessingException {//真实的开发一般都使用json来传递对象User user new User(java, 3);//String jsonUser new ObjectMapper().writeValueAsString(user);redisTemplate.opsForValue().set(user,user);Object user1 redisTemplate.opsForValue().get(user); //直接传递对象会报错所有的对象传递要先序列化System.out.println(user1);}在企业开发中我们大部分情况下都不会使用这种原生的方式去编写代码而是封装成工具类RedisUtils
package com.example.utils;import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;Component
public class RedisUtil {Autowiredprivate RedisTemplateString, Object redisTemplate;public void setRedisTemplate(RedisTemplateString, Object redisTemplate) {this.redisTemplate redisTemplate;}// common/*** 指定缓存失效时间** param key 键* param time 时间(秒)* return*/public boolean expire(String key, long time) {try {if (time 0) {redisTemplate.expire(key, time, TimeUnit.SECONDS);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 判断key是否过期** param key* return*/public boolean isExpire(String key) {return getExpire(key) 1 ? false : true;}/*** 根据key 获取过期时间** param key 键 不能为null* return 时间(秒) 返回0代表为永久有效*/public long getExpire(String key) {return redisTemplate.getExpire(key, TimeUnit.SECONDS);}/*** 判断key是否存在** param key 键* return true 存在 false不存在*/public boolean hasKey(String key) {try {return redisTemplate.hasKey(key);} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除缓存** param key 可以传一个值 或多个*/SuppressWarnings(unchecked)public void del(String... key) {if (key ! null key.length 0) {if (key.length 1) {redisTemplate.delete(key[0]);} else {redisTemplate.delete((CollectionString) CollectionUtils.arrayToList(key));}}}// String/*** 普通缓存获取** param key 键* return 值*/public Object get(String key) {return key null ? null : redisTemplate.opsForValue().get(key);}/*** 普通缓存放入** param key 键* param value 值* return true成功 false失败*/public boolean set(String key, Object value) {try {redisTemplate.opsForValue().set(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间** param key 键* param value 值* param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期* return true成功 false 失败*/public boolean set(String key, Object value, long time) {try {if (time 0) {redisTemplate.opsForValue().set(key, value, time, TimeUnit.SECONDS);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 普通缓存放入并设置时间** param key 键* param value 值* param time 时间(秒) time要大于0 如果time小于等于0 将设置无限期* return true成功 false 失败*/public boolean set(String key, Object value, long time, TimeUnit timeUnit) {try {if (time 0) {redisTemplate.opsForValue().set(key, value, time, timeUnit);} else {set(key, value);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 递增** param key 键* param delta 要增加几* return*/public long incr(String key, long delta) {if (delta 0) {throw new RuntimeException(递增因子必须大于0);}return redisTemplate.opsForValue().increment(key, delta);}/*** 递减** param key 键* param delta 要减少几* return*/public long decr(String key, long delta) {if (delta 0) {throw new RuntimeException(递减因子必须大于0);}return redisTemplate.opsForValue().increment(key, -delta);}// Map/*** HashGet** param key 键 不能为null* param item 项 不能为null* return 值*/public Object hget(String key, String item) {return redisTemplate.opsForHash().get(key, item);}/*** 获取hashKey对应的所有键值** param key 键* return 对应的多个键值*/public MapObject, Object hmget(String key) {return redisTemplate.opsForHash().entries(key);}/*** HashSet** param key 键* param map 对应多个键值* return true 成功 false 失败*/public boolean hmset(String key, MapString, Object map) {try {redisTemplate.opsForHash().putAll(key, map);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** HashSet 并设置时间** param key 键* param map 对应多个键值* param time 时间(秒)* return true成功 false失败*/public boolean hmset(String key, MapString, Object map, long time) {try {redisTemplate.opsForHash().putAll(key, map);if (time 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** param key 键* param item 项* param value 值* return true 成功 false失败*/public boolean hset(String key, String item, Object value) {try {redisTemplate.opsForHash().put(key, item, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 向一张hash表中放入数据,如果不存在将创建** param key 键* param item 项* param value 值* param time 时间(秒) 注意:如果已存在的hash表有时间,这里将会替换原有的时间* return true 成功 false失败*/public boolean hset(String key, String item, Object value, long time) {try {redisTemplate.opsForHash().put(key, item, value);if (time 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 删除hash表中的值** param key 键 不能为null* param item 项 可以使多个 不能为null*/public void hdel(String key, Object... item) {redisTemplate.opsForHash().delete(key, item);}/*** 判断hash表中是否有该项的值** param key 键 不能为null* param item 项 不能为null* return true 存在 false不存在*/public boolean hHasKey(String key, String item) {return redisTemplate.opsForHash().hasKey(key, item);}/*** hash递增 如果不存在,就会创建一个 并把新增后的值返回** param key 键* param item 项* param by 要增加几(大于0)* return*/public double hincr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, by);}/*** hash递减** param key 键* param item 项* param by 要减少记(小于0)* return*/public double hdecr(String key, String item, double by) {return redisTemplate.opsForHash().increment(key, item, -by);}// set/*** 根据key获取Set中的所有值** param key 键* return*/public SetObject sGet(String key) {try {return redisTemplate.opsForSet().members(key);} catch (Exception e) {e.printStackTrace();return null;}}/*** 根据value从一个set中查询,是否存在** param key 键* param value 值* return true 存在 false不存在*/public boolean sHasKey(String key, Object value) {try {return redisTemplate.opsForSet().isMember(key, value);} catch (Exception e) {e.printStackTrace();return false;}}/*** 将数据放入set缓存** param key 键* param values 值 可以是多个* return 成功个数*/public long sSet(String key, Object... values) {try {return redisTemplate.opsForSet().add(key, values);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 将set数据放入缓存** param key 键* param time 时间(秒)* param values 值 可以是多个* return 成功个数*/public long sSetAndTime(String key, long time, Object... values) {try {Long count redisTemplate.opsForSet().add(key, values);if (time 0) {expire(key, time);}return count;} catch (Exception e) {e.printStackTrace();return 0;}}/*** 获取set缓存的长度** param key 键* return*/public long sGetSetSize(String key) {try {return redisTemplate.opsForSet().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 移除值为value的** param key 键* param values 值 可以是多个* return 移除的个数*/public long setRemove(String key, Object... values) {try {Long count redisTemplate.opsForSet().remove(key, values);return count;} catch (Exception e) {e.printStackTrace();return 0;}}// list/*** 获取list缓存的内容** param key 键* param start 开始* param end 结束 0 到 -1代表所有值* return*/public ListObject lGet(String key, long start, long end) {try {return redisTemplate.opsForList().range(key, start, end);} catch (Exception e) {e.printStackTrace();return null;}}/*** 获取list缓存的长度** param key 键* return*/public long lGetListSize(String key) {try {return redisTemplate.opsForList().size(key);} catch (Exception e) {e.printStackTrace();return 0;}}/*** 通过索引 获取list中的值** param key 键* param index 索引 index0时 0 表头1 第二个元素依次类推index0时-1表尾-2倒数第二个元素依次类推* return*/public Object lGetIndex(String key, long index) {try {return redisTemplate.opsForList().index(key, index);} catch (Exception e) {e.printStackTrace();return null;}}/*** 将list放入缓存** param key 键* param value 值* return*/public boolean lSet(String key, Object value) {try {redisTemplate.opsForList().rightPush(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** param key 键* param value 值* param time 时间(秒)* return*/public boolean lSet(String key, Object value, long time) {try {redisTemplate.opsForList().rightPush(key, value);if (time 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** param key 键* param value 值* return*/public boolean lSet(String key, ListObject value) {try {redisTemplate.opsForList().rightPushAll(key, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 将list放入缓存** param key 键* param value 值* param time 时间(秒)* return*/public boolean lSet(String key, ListObject value, long time) {try {redisTemplate.opsForList().rightPushAll(key, value);if (time 0) {expire(key, time);}return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 根据索引修改list中的某条数据** param key 键* param index 索引* param value 值* return*/public boolean lUpdateIndex(String key, long index, Object value) {try {redisTemplate.opsForList().set(key, index, value);return true;} catch (Exception e) {e.printStackTrace();return false;}}/*** 移除N个值为value** param key 键* param count 移除多少个* param value 值* return 移除的个数*/public long lRemove(String key, long count, Object value) {try {Long remove redisTemplate.opsForList().remove(key, count, value);return remove;} catch (Exception e) {e.printStackTrace();return 0;}}}
测试,有了工具类后使用更加方便 Autowiredprivate RedisUtils redisUtils;Testpublic void test1(){redisUtils.set(name,xqh);System.out.println(redisUtils.get(name));}