NoSQL(Not Only SQL
),意即不仅仅是SQL, 泛指非关系型的数据库。Nosql这个技术门类,早期就有人提出,发展至2009年趋势越发高涨。
随着互联网网站的兴起,传统的关系数据库在应付动态网站,特别是超大规模和高并发的纯动态网站已经显得力不从心,暴露了很多难以克服的问题。如商城网站中对商品数据频繁查询
、对热搜商品的排行统计
、订单超时问题
、以及微信朋友圈(音频,视频)存储等相关使用传统的关系型数据库实现就显得非常复杂,虽然能实现相应功能但是在性能上却不是那么乐观。nosql这个技术门类的出现,更好的解决了这些问题,它告诉了世界不仅仅是sql。
# 1.说明:
- 这一类数据库主要会使用到一个哈希表,这个表中有一个特定的键和一个指针指向特定的数据。
# 2.特点
- Key/value模型对于IT系统来说的优势在于简单、易部署。
- 但是如果DBA只对部分值进行查询或更新的时候,Key/value就显得效率低下了。
# 3.相关产品
- Tokyo Cabinet/Tyrant,
- Redis 基于内存的 运行软件--->磁盘--->内存中
- SSDB 基于磁盘的 直接与磁盘做交互--> IO
- Voldemort
- Oracle BDB
# 1.说明
- 这部分数据库通常是用来应对分布式存储的海量数据。
# 2.特点
- 键仍然存在,但是它们的特点是指向了多个列。这些列是由列家族来安排的。列簇
- rowkey
# 3.相关产品
- Cassandra、`HBase`、Riak.
# 1.说明
- 文档型数据库的灵感是来自于Lotus Notes办公软件的,而且它同第一种键值存储相类似该类型的数据模型是版本化的文档,半结构化的文档以特定的格式存储,比如JSON。文档型数据库可 以看作是键值数据库的升级版,允许之间嵌套键值。而且文档型数据库比键值数据库的查询效率更高
{'id':1001,'name':xiaohu}
{'id':1001,'name':'xiaohu2,'address':'anhuihefei','likes':['play','eat'],'study':{'yuyan':java,'ruanjian':'mysql'}}
文档数据库对于单条数据来说,他的事务支持并没有那么强大
目前的mongodb5,支持了单条数据的事务,但是多条不行
# 2.特点
- 以文档形式存储
# 3.相关产品
- `MongoDB`、CouchDB、 MongoDb(4.x). 国内也有文档型数据库SequoiaDB,已经开源。
# 1.说明
- 图形结构的数据库同其他行列以及刚性结构的SQL数据库不同,它是使用灵活的图形模型,并且能够扩展到多个服务器上。
# 2.特点
- NoSQL数据库没有标准的查询语言(SQL),因此进行数据库查询需要制定数据模型。许多NoSQL数据库都有REST式的数据接口或者查询API。
# 3.相关产品
- Neo4J、InfoGrid、 Infinite Graph、
数据模型比较简单
需要灵活性更强的IT系统
对数据库性能要求较高
不需要高度的数据一致性(NoSql数据库对事物的支持都不是太好)
Redis is an open source (BSD licensed), in-memory data structure store used as a database, cache, message broker, and streaming engine.
Redis 开源 遵循BSD 基于内存数据存储 被用于作为 数据库 缓存 消息中间件
总结: redis是一个内存型的数据库
Redis是一个高性能key/value内存型数据库 在redis中,所有的数据形式都是以键值对的方式来存储的
Redis支持丰富的数据类型 string,list,set,sorted set 指的是键值对中的值的类型
Redis支持持久化 持久化:将数据落盘,明天会详细说一说redis中的持久化
Redis单线程,单进程 由于是单线程和单进程的,所以它的线程是安全的,我们之前说的java中的多线程安全在分布式中不起作用,当时只针对一个JVM中是有效的。
# 0.准备环境
- vmware 12.x+
- centos7.x+
# 1.下载redis源码包
- https://redis.io/
# 2.下载完整源码包
- redis-7.0.10.tar.gz
# 3.将下载redis资料包上传到Linux中
# 4.解压缩文件
[root@localhost ~]# tar -zxvf redis-7.0.10.tar.gz
[root@localhost ~]# ll
redis底层是由C语言编写的
# 9.Redis服务端口默认是 6379
# 11.连接成功出现上面界面连接成功
简单测试成功,给一个键值对,根据键获取值,获取所有的键
注意:(说这个之前,需要带学生写一个配置文件的修改和使用,库的细节)
# 1.Redis中库说明
# 1.DEL指令
命令
说明
set
设置一个key/value
get
根据key获得对应的value
mset
一次设置多个key value
mget
一次获得多个key的value
getset
获得原始key的值,同时设置新值
strlen
获得对应key存储value的长度
append
为对应key的value追加内容
getrange 索引0开始
截取value的内容 到末尾-1
setex
设置一个key存活的有效期(秒)
psetex
设置一个key存活的有效期(毫秒)
setnx
存在不做任何操作,不存在添加
msetnx原子操作(只要有一个存在不做任何操作)
可以同时设置多个key,只有有一个存在都不保存
decr
进行数值类型的-1操作
decrby
根据提供的数据进行减法操作
Incr
进行数值类型的+1操作
incrby
根据提供的数据进行加法操作
Incrbyfloat
根据提供的数据加入浮点数(不是四舍五入)
list 列表 相当于java中list 集合 特点 元素有序 且 可以重复,key还是一个字符串,值是一个list
命令
说明
lpush
将某个值加入到一个key列表头部 lpush list xiaohu xiaohei xiaoming 当列表不存在的时候会进行创建
lpushx
同lpush,但是必须要保证这个key存在 必须在列表进行存在的情况下从左插入
rpush
将某个值加入到一个key列表末尾
rpushx
同rpush,但是必须要保证这个key存在
lpop
返回和移除列表左边的第一个元素
rpop
返回和移除列表右边的第一个元素
lrange
获取某一个下标区间内的元素 lrange list 0 -1
llen
获取列表元素个数
lset
设置某一个指定索引的值(索引必须存在)
lindex
获取某一个指定索引位置的元素
lrem
删除重复元素
ltrim
保留列表中特定区间内的元素
linsert
在某一个元素之前,之后插入新元素
特点: Set类型 Set集合 元素无序 不可以重复
命令
说明
sadd
为集合添加元素
smembers
显示集合中所有元素 无序
scard
返回集合中元素的个数
spop
随机返回一个元素 并将元素在集合中删除
smove
从一个集合中向另一个集合移动元素 必须是同一种类型
srem
从集合中删除一个元素
sismember
判断一个集合中是否含有这个元素
srandmember
随机返回元素 后面可以加数字 表示每次返回的个数
sdiff
去掉第一个集合中其它集合含有的相同元素
sinter
求交集
sunion
求和集
特点: 可排序的set集合 排序 不可重复
ZSET 官方 可排序SET sortSet
命令
说明
zadd
添加一个有序集合元素 zadd zset 2 xiaohu 3 xiaohu2
zcard
返回集合的元素个数
zrange 升序 zrevrange 降序
返回一个范围内的元素 如果想看看分数 withscores
zrangebyscore
按照分数查找一个范围内的元素 zrangebyscore zset 0 20 withscores limit 0 2
zrank
返回排名
zrevrank
倒序排名
zscore
显示某一个元素的分数
zrem
移除某一个元素
zincrby
给某个特定元素加分
特点: value 是一个map结构 存在key value key 无序的
redis key(String) value(map)
Map
举例:map name zhangsan
命令
说明
hset
设置一个key/value对
hget
获得一个key对应的value
hgetall
获得所有的key/value对
hdel
删除某一个key/value对
hexists
判断一个key是否存在
hkeys
获得所有的key
hvals
获得所有的value
hmset
设置多个key/value
hmget
获得多个key的value
hsetnx
设置一个不存在的key的值
hincrby
为value进行加法运算
hincrbyfloat
为value加入浮点值
第一天说完上面知识点后,介绍可视化工具的安装使用(引入修改配置文件,使得远程连接)mac电脑的叫做medis https://getmedis.com/
下载官网:https://redisdesktop.com/download
注意问题:
1、如果还是连接不上,查看防火墙
2、端口被占用,可能是redis服务起多了 ps aux|grep redis
client redis[内存] -----> 内存数据- 数据持久化-->磁盘
Redis官方提供了两种不同的持久化方法来将内存的数据存储到硬盘里面分别是:
快照(Snapshot)
AOF (Append Only File) 只追加日志文件
这种方式可以将某一时刻的所有数据都写入硬盘中,当然这也是redis的默认开启持久化方式,保存的文件是以.rdb形式结尾的文件因此这种方式也称之为RDB方式。
官方说法叫快照持久化
客户端方式: BGSAVE 和 SAVE指令
服务器配置自动触发
# 1.客户端方式之BGSAVE
a.客户端可以使用BGSAVE命令来创建一个快照,当接收到客户端的BGSAVE命令时,redis会调用fork¹来创建一个子进程,然后子进程负责将快照写入磁盘中,而父进程则继续处理命令请求。
`名词解释: fork当一个进程创建子进程的时候,底层的操作系统会创建该进程的一个副本,在类似于unix系统中创建子进程的操作会进行优化:在刚开始的时候,父子进程共享相同内存,直到父进程或子进程对内存进行了写之后,对被写入的内存的共享才会结束服务`
# 2.客户端方式之SAVE
b.客户端还可以使用SAVE命令来创建一个快照,接收到SAVE命令的redis服务器在快照创建完毕之前将不再响应任何其他的命令
注意: SAVE命令并不常用,使用SAVE命令在快照创建完毕之前,redis处于阻塞状态,无法对外服务
# 3.服务器配置方式之满足配置自动触发
# 4.服务器接收客户端shutdown指令
#1.修改生成快照名称
演示断电操作,这个持久化并不是太好,可能会造成数据丢失的问题(刚刚做完一次快照,又来了写数据请求断电)
这种方式可以将所有客户端执行的写命令记录到日志文件中,AOF持久化会将被执行的写命令写到AOF的文件末尾,以此来记录数据发生的变化,因此只要redis从头到尾执行一次AOF文件所包含的所有写命令,就可以恢复AOF文件的记录的数据集.
在redis的默认配置中AOF持久化机制是没有开启的,需要在配置中开启
# 1.开启AOF持久化
# 1.always 【谨慎使用】
# 1.修改日志同步频率
AOF的方式也同时带来了另一个问题。持久化文件会变的越来越大。例如我们调用incr test命令100次,文件中必须保存全部的100条命令,其实有99条都是多余的。因为要恢复数据库的状态其实文件中保存一条set test 100就够了。为了压缩aof的持久化文件Redis提供了AOF重写(ReWriter)机制。
用来在一定程度上减小AOF文件的体积,并且还能保证数据不丢失
# 1.客户端方式触发重写
从 Redis 7.0.0 开始,Redis 使用了多部分 AOF 机制。也就是将原来的单个AOF文件拆分为基础文件(最多一个)和增量文件(可能不止一个)。基本文件表示重写AOF 时存在的数据的初始(RDB 或 AOF 格式)快照。增量文件包含自创建最后一个基本 AOF 文件以来的增量更改。所有这些文件都放在一个单独的目录中,并由清单文件跟踪。
从 Redis 7.0.0 开始,在调度 AOF 重写时,Redis 父进程会打开一个新的增量 AOF 文件继续写入。子进程执行重写逻辑并生成新的基础 AOF。Redis 将使用一个临时清单文件来跟踪新生成的基础文件和增量文件。当它们准备好后,Redis 会执行原子替换操作,使这个临时清单文件生效。为了避免在 AOF 重写重复失败和重试的情况下创建大量增量文件的问题,Redis 引入了 AOF 重写限制机制,以确保失败的 AOF 重写以越来越慢的速度重试。
注意:重写aof文件的操作,并没有读取旧的aof文件,而是将整个内存中的数据库内容用命令的方式重写了一个新的aof文件,替换原有的文件这点和快照有点类似。
# 重写流程
Redis7.0.0之前:
Redis7.0.0之后:
两种持久化方案既可以同时使用(aof),又可以单独使用,在某种情况下也可以都不使用,具体使用那种持久化方案取决于用户的数据和应用决定。
无论使用AOF还是快照机制持久化,将数据持久化到硬盘都是有必要的,除了持久化外,用户还应该对持久化的文件进行备份(最好备份在多个不同地方)。
零存零取,整存零取,整存整存
位图不是真正的数据类型,它是定义在字符串类型中,一个字符串类型的值最多能存储512M字节的内容
位上限:2^(9(512)+10(1024)+10(1024)+3(8b=1B))=2^32b
语法:SETBIT key offset value (offset位偏移量,从0开始)
127.0.0.1:7000> flushall
OK
127.0.0.1:7000> setbit k1 1 1
0
127.0.0.1:7000> get k1
@
127.0.0.1:7000> setbit k1 7 1
0
127.0.0.1:7000> get k1
A
127.0.0.1:7000> setbit k1 7 2
ERR bit is not an integer or out of range
127.0.0.1:7000> setbit k1 9 1
0
127.0.0.1:7000> get k1
A@
语法:GETBIT key offset
127.0.0.1:7000> getbit k1 7
1
127.0.0.1:7000> getbit k1 8
0
127.0.0.1:7000> getbit k1 1
1
语法:BITPOS key bit [start] [end](字节索引,0表示第一个字节)
summary: Find first bit set or clear in a string since: 2.8.7 group: string
不指定查找范围,表示从全部内容中查找:BITPOS key bit
127.0.0.1:7000> keys *
k1
127.0.0.1:7000> bitpos k1 1
1
127.0.0.1:7000> setbit k1 1 0
1
127.0.0.1:7000> bitpos k1 1
7
127.0.0.1:7000> setbit k1 7 0
1
127.0.0.1:7000> bitpos k1 1
9
指定查找范围:
BITPOS key bit start :从start+1个字节开始查找,直到尾部 BITPOS key bit start end:从start+1字节开始到end+1字节之间查找
然后将数据还原:
127.0.0.1:7000> setbit k1 1 1
0
127.0.0.1:7000> setbit k1 7 1
0
查找演示:
127.0.0.1:7000> bitpos k1 1 0 0
1 #在第一个字节中查找1首次出现的下标
127.0.0.1:7000> bitpos k1 1 0
1 #从第一个字节到值得最后一个字节查找1首次出现的下标
127.0.0.1:7000> setbit k1 1 0
1 #将指定下标的值改为0
127.0.0.1:7000> bitpos k1 1 0 0
7 #
127.0.0.1:7000> bitpos k1 1 0
7
127.0.0.1:7000> setbit k1 7 0
1
127.0.0.1:7000> bitpos k1 1 0 0
-1 #在第一个字节中没有找到1,则返回-1
127.0.0.1:7000> bitpos k1 1 0
9 #从第一个字节到值得最后一个字节查找
127.0.0.1:7000> bitpos k1 1 0 1
9 #在第1和第2个字节总找1首次出现的位置
127.0.0.1:7000> bitpos k1 1 0 2
9 #在第1到第3个字节查找1首次出现的位置,但数据总共2(小于end对应的3)个字节,不会抛错。
语法:BITOP operation destkey key [key …]
summary: Perform bitwise operations between strings since: 2.6.0 group: string
对一个或多个保存二进制位的字符串 key 进行位操作,并将结果保存到 destkey 上。operation 可以是 AND 、 OR 、 NOT 、 XOR 这四种操作中的任意一种
BITOP AND destkey key [key …] ,对一个或多个 key 求逻与,并将结果保存到 destkey
BITOP OR destkey key [key …] ,对一个或多个 key 求逻辑或,并将结果保存到 destkey
BITOP XOR destkey key [key …] ,对一个或多个 key 求逻辑异或,并将结果保存到 destkey
BITOP NOT destkey key ,对给定 key 求逻辑非,并将结果保存到 destkey
除了 NOT 操作之外,其他操作都可以接受一个或多个 key 作为输入,当 BITOP 处理不同长度的字符串时,较短的那个字符串所缺少的部分会被看作 0,空的 key 也被看作是包含 0 的字符串序列
BITOP AND destkey key [key …]演示:
127.0.0.1:7000> flushall
OK
127.0.0.1:7000> keys *
(empty list or set)
127.0.0.1:7000> setbit k1 1 1
(integer) 0
127.0.0.1:7000> setbit k2 7 1
(integer) 0
127.0.0.1:7000> bitop and k3 k1 k2
(integer) 1
127.0.0.1:7000> get k3
"\x00"
BITOP OR destkey key [key …]演示
127.0.0.1:7000> bitop or k4 k1 k2
(integer) 1
127.0.0.1:7000> get k4
"A"
BITOP XOR destkey key [key …]
127.0.0.1:7000> bitop xor k5 k1 k2
(integer) 1
127.0.0.1:7000> get k5
"A"
127.0.0.1:7000> bitop not k6 k1
(integer) 1
127.0.0.1:7000> get k6
"\xbf"
统计指定位区间上值为1的个数
从左向右从0开始,注意官方start、end是位,测试后是字节
127.0.0.1:7000> get k1
"@"
127.0.0.1:7000> bitcount k1
(integer) 1
127.0.0.1:7000> setbit k1 7 1
(integer) 0
127.0.0.1:7000> bitcount k1
(integer) 2
127.0.0.1:7000> setbit k1 9 1
(integer) 0
127.0.0.1:7000> bitcount k1
(integer) 3 #统计全部的1的总数
127.0.0.1:7000> bitcount k1 0 0
(integer) 2 #统计第一个字节中1出现的总数
127.0.0.1:7000> bitcount k1 0 1
(integer) 3 #统计第0+1到第1+1字节中1出现的总数
从右向左从-1开始,注意官方start、end是位,测试后是字节
127.0.0.1:7000>BITCOUNT k1 0 -1 #等同于BITCOUNT k1
(integer) 3
最常用的就是 BITCOUNT k1
127.0.0.1:7000> set k7 ab
OK
127.0.0.1:7000> get k7
"ab"
127.0.0.1:7000> bitcount k7
(integer) 6
127.0.0.1:7000> bitcount k7 0 0
(integer) 3
127.0.0.1:7000> bitcount k7 1 1
(integer) 3
127.0.0.1:7000> set k8 中
OK
127.0.0.1:7000> bitcount k8
(integer) 13
127.0.0.1:7000> get k8
"\xe4\xb8\xad"
用户ID为key,天作为offset,上线置为1 366> 000000000000000
366 /8=46Byte ID为18的用户,今年的第1天签到、第30天签到
127.0.0.1:7000[2]> setbit u18 1 1
(integer) 0
127.0.0.1:7000[2]> setbit u18 30 1
(integer) 0
127.0.0.1:7000[2]> bitcount u18 #统计id为18的用户签到总次数
(integer) 2
127.0.0.1:7000[2]> keys u*
1) "u18"
天作为key,用户ID为offset,上线置为1
求一段时间内活跃用户数 5000 0000 / 8_366= 6.3MB=_366 (五千万活跃用户1年才产生2GB左右的数据)
127.0.0.1:7000>SETBIT 20190601 5 1 #0000 0100
127.0.0.1:7000>SETBIT 20190602 7 1 #0000 0001
127.0.0.1:7000>SETBIT 20190603 7 1 #0000 0001
求6月1日到6月10日的活跃用户数
127.0.0.1:7000>BITOP OR users 20190601 20190602 20190603 … 20190610
127.0.0.1:7000>BITCOUNT users #目标key为users
结果为2
127.0.0.1:7000> SETBIT online 5 1 #0000 0100 上线为1
(integer) 0
127.0.0.1:7000> SETBIT online 7 1 #0000 0101
(integer) 0
127.0.0.1:7000> bitcount online #当前在线人数
(integer) 2
127.0.0.1:7000> SETBIT online 7 0
(integer) 1
127.0.0.1:7000> bitcount online #当前在线人数
(integer) 1
public static void main(String[] args) {
//1.创建jedis对象
Jedis jedis = new Jedis("192.168.40.110", 7000);//1.redis服务必须关闭防火墙 2.redis服务必须开启远程连接
jedis.select(0);//选择操作的库默认0号库
//2.执行相关操作
//….
//3.释放资源
jedis.close();
}
//测试与key相关的操作
@Test
public void testKey(){
jedis.set("name","xiaohu");
jedis.set("age","18");
jedis.set("age1","19");
jedis.set("age2","20");
jedis.set("age3","21");
//删除一个键
long l = jedis.del("age1");
if(l==1){
System.out.println("成功删除age1键");
}
//删除多个键
long l2 = jedis.del("age2", "age3");
if(l2>1){
System.out.println("成功删除多个键");
}
//判断是否存在
boolean name = jedis.exists("age1");
if(name==true){
System.out.println("键存在");
}
jedis.expire("age",10L);
}
@Test
public void testString(){
jedis.decrBy("age",255l);
jedis.incr("age");
}
@Test
public void testList (){
jedis.lpush("l1","name","age","xingbie","address");
jedis.lrange("l1",0,-1);
jedis.type("l1");
jedis.llen("l1");
jedis.lpop("l1",1);
jedis.lrem("l1",1,"lisi");
jedis.linsert("l1", ListPosition.valueOf("before"), "name", "class");
jedis.linsert("l1","");
}
@Test
public void testSet(){
jedis.sadd("set1","name","xiaoming" ,"xiaobai", "xiaohu" ,"xiaohong", "xiaocai" ,"xiaoshui");
jedis.keys("*");
jedis.smembers("set1");
jedis.sadd("set2","wangwu" ,"zhaoliu" , "wangermazi", "minli");
jedis.smembers("set2");
jedis.scard("set1");
jedis.spop("set2");
jedis.smove("set1","set2","name");
jedis.sismember("set1","xiaoming");
jedis.srandmember("set1",1);
jedis.sadd("set1", "java" ,"hoodoop" ,"spark" ,"python");
jedis.sadd("set1", "java" ,"hoodoop" ,"spark" ,"python","mysql" ,"redis", "maven");
jedis.sdiff("set1","set2");
jedis.sinter("set1","set2");
jedis.sunion("set1","set2");
}
@Test
public void TestZset() {
jedis.zadd("zset1", 20l, "xiaoming");
jedis.zadd("zset1", 2l, "xiaoxin");
jedis.zadd("zset1", 5l, "xiaofang");
jedis.zrange("zset1",0,-1);
jedis.zrangeByScoreWithScores("zset1",0,10);
jedis.zrangeWithScores("zset1",0,-1);
jedis.zrank("zset1","xiaoming");
jedis.zscore("zset1","xiaoxin");
jedis.zincrby("zset1",25l,"xiaoming");
jedis.select(1);
}
@Test
public void testHash(){
jedis.hset("map1","age","25");
jedis.hset("map1","name","xiaohua");
jedis.hset("map1","sex","nv");
jedis.hgetAll("map1");
jedis.mset("map2", "name", "wangyouhu" ,"age", "18");
jedis.hgetAll("map2");
jedis.hsetnx("map3", "name"," xiaofang");
jedis.hgetAll ("map3");
long l = jedis.hincrBy("map1","age",15l);
jedis.hincrByFloat("map1","age",32.12f);
jedis.hgetAll("map1");
}
Spring Boot Data(数据) Redis 中提供了RedisTemplate和StringRedisTemplate,其中StringRedisTemplate是RedisTemplate的子类,两个方法基本一致,不同之处主要体现在操作的数据类型不同,RedisTemplate中的两个泛型都是Object,意味着存储的key和value都可以是一个对象,而StringRedisTemplate的两个泛型都是String,意味着StringRedisTemplate的key和value都只能是字符串。
注意: 使用RedisTemplate默认是将对象序列化到Redis中,所以放入的对象必须实现对象序列化接口
spring.redis.host=192.168.40.110
spring.redis.port=7000
spring.redis.database=0
手机扫一扫
移动阅读更方便
你可能感兴趣的文章