Redis
举例:Redirs缓存式数据库,比如双十一客户下单买东西,加入购物车中但是没买,数据库的库存这时候数量就会减一,但是这订单是有过期时间的,并没有持久化数据库中,缓存数据库中的数据适合那些经常查询并且不重要的数据
关系型数据库 数据直接存储到硬盘上的 IO mysql
缓存 基于内存
mybatis
非关系型数据库 NoSql Not Only Sql
关系型数据库和非关系型数据库(NoSql)的对比
优点:
-
部署简易,免费开源,成本低
-
查询速度快:nosql服务器将数据存储在内存中,关系型数据库是把数据存储在硬盘上
-
存储数据的格式不相同:nosql存储数据的格式是key-value、文档型、图片,还可以存储对象和集合类型等,关系型数据库大多存储的是基本类型
-
扩展性:在关系型数据库中进行多表查询时扩展性较差
主流的Nosql数据库产品
-
键值(key-value) 存储数据库
相关产品:Redis、DB、Tokyo
应用: 内容缓存 主要是用于解决大量数据的高访问负载。
数据模型:一系列键值对
优势: 查询速度非常快
劣势:存储的数据的缺少结构化
-
列存储数据库:
相关产品:Hbase
典型应用:分布式的文件系统
数据模型:以列簇的形式存储,将同一列的数据存储在一起
优势: 查询速度非常快,可扩展性较强,容易进行分布式扩展
劣势:功能局限性较大
-
文档型数据库
相关产品:MongoDB
典型应用:web应用中 (和key-value类似,value是 结构化的)
数据模型:一系列键值对
优势:数据结构要求不严格
劣势:查询性能不高,并且缺乏统一的查询的语法
-
图形数据库 Graph
相关产品: Graph Neo4J
典型应用:社交网络
数据模型:图结构
优势:利用图结构进行相关优化算法
劣势:需要对整个图做计算才能得出结果,不容易进行分布式集群的使用。
Redis概述
Redis产品是由C语言开发的一个开源的免费的键值对存储数据库,官方提供的数据库只有linux版
没有window版,对于50个并发,执行10万次请求,读的速度是110000次/s,写的速度在 81000次/s
它提供了多种键值类型满足多样化的需求,对于redis而言键的类型一般都是字符串,对应的值的类型一般有5中类型
字符串类型String
散列类型 hash
列表类型 list
集合类型 set
有序集合类型 sorted set
Redis的使用场景
-
令牌的生成 Token 类似于session中的那个 sessionID
-
短信验证码 code
-
可以实现缓存查询数据 减轻数据库服务器的压力
-
Redis帮助实现计数器
-
分布式锁
-
延迟操作
-
日志记录
-
分布式集群的session的分离
安装
官方推荐的是在linux系统中进行安装的,同样也可以在window系统中进行安装
windows版不是官方版本,
我们的安装在Linux环境中进行安装
又因为Redis是由C语言写的,所以我们需要C语言的编译环境 ,先编译后再安装
启动后的默认端口是 【6379】
安装步骤待续。。。
Redis数据结构
-
redis是一种高级的key-value的数据库存储系统,其中value值支持5种数据类型 ,key数据类型一般都是string
-
字符串类型 string
-
散列类型 hash
-
列表类型 list
-
集合类型 set
-
有序集合类型 sorted set
-
-
对于redis的key值,如果定义的名称过长 ,查询效率会降低,按规范命名
命令
-
测试连接是否成功 使用ping 成功会显示pong
-
redis默认在空间生成16个数据库,数据库的编号依次从0~15,默认使用的是0号数据库 select 0~15
使用select index值 选择对应的数据库
-
显示所有的key 使用 keys *
-
使用指令 keys a?查询a开头的,长度为2的 key名称
-
-
清空所有数据
-
删除key 使用 del key名称 删除多个key值 del key1 key2。。。。
-
校验key值是否存在 exists key 1代表存在 0代表不存在
-
给key值进行重命名 rename key旧名称 key新名称
-
给当前key值设置过期时间值,单位为秒 expire key 秒数
-
查看过期key值剩余的时间值 ttl key 如果该key值存在显示剩余的时间,如果该key没有设置过期时间
显示 -1 如果超时了 显示-2
-
-
查看key的指定数据类型 type key 返回值 string hash set list zset
String类型
字符串类型是redis数据库中最基础最常用的数据类型,并且在redis中是二进制安全的,
该字符串类型可以接受任何类型的数据,在Redis中字符串类型的value值最多可以容纳的数据长度为512M
-
设置键值对 set key value
-
设置多个键值对 mset key1 value1 key2 value2 。。。。
-
通过key值获取value值 get key 如果不存在返回【nil】
-
删除key del key
-
先获取key的值,再设置key的值 getset key value
-
让key对应的value值增加相应的数字 incr key 默认增加1
-
让key对应的value值减少1 decr key 默认减少1
-
增加多个数值 incrby key 增加的数字
-
减少多个数值 decrby key 减少的数字
-
在key对应的value值后面追加信息 append key value 如果不存在直接新建附上相应的值
Hash类型
散列类型可以看做成String,key是String,value是一个map容器(key-value)
在hash类型中非常适合存储值(JavaBean)对象的信息
比如个人的信息 username age address password可以使用hash类型存储
每一个hash值可以存储42亿多个键值对信息
-
赋值
-
hset key field value 给指定的key设定field/value键值对值 设置一个
-
hmset key field1 value1 field2 value2...... 给指定的key设置field/value对多个信息
-
-
取值
-
hget key field 获取指定的key中field对应的value值
-
hmget key field1 field2 ....... 获取指定key中field1、field2对应的value值
-
hgetall key 获取指定key中所有的field/value值
-
-
删除
-
hdel key field1 field2..... 删除指定key中field1、field2对应的值
-
del key 删除整个key对应的内容
-
-
增加
-
hincrby key field 增加的数值
-
-
hexists key field 判断指定key中的field是否存在
-
hlen key 获取key所包含的field的数量
-
hkeys key 获取所有的key
-
hvals key 获取所有value
List类型
在Redis中,List类型是按照插入顺序排序的字符串链表
和数据结构中的普通链表一样,我们在头部(left)和尾部(right)添加新元素,在插入时,如果该键不存在
Redis将为该键创建一个新的链表。相反,如果链表中所有的元素均被移除,那么该键也将会从数据库中删除
List中可以包含的最大元素数量是42亿多个。
从 元素插入和删除的效率来看,如果我们是在链表的两端插入和删除,效率非常高;如果是从中间进行元素的插入和删除,效率较低
-
两端添加
-
lpush key value1 value2 value3.... 通过指定的key存放多个value值,在list的头部插入所有的value值,
如果该key不存在,该命令在插入之前创建一个与key关联的空链表,之后再把所有的value值在该空链表的头部依次插入,如果插入成功,返回元素的个数
-
rpush key value1 value2 value3...... 通过指定的key存放多个value值,在list的尾部添加元素
-
lpushx key value 仅当参数中指定的key存在时,在指定的key所关联的list的头部插入value值
-
rpushx key value 在list的尾部添加元素
-
-
查看列表
-
lrange key start end 获取链表中从start到end的元素的值 start、end可以为负数,如果为-1表示链表尾部的元素,-2则表示倒数第二个 -3倒数第三个
-
-
两端弹出
-
lpop key 返回并弹出指定key关联的链表中的第一个元素,即头部元素
-
rpop key 从尾部弹出元素
-
-
llen key 返回指定的key关联的链表中的元素的个数
-
linsert key before | after pivot value 在pivot元素的前或者后插入value值
Set类型
在Redis中,我们可以把set类型理解成没有排序的字符集合
和List类型一样,我们也可以在该类型的的数据值上进行添加、删除或者判断某一元素是否存在等操作
Set可包含的最大元素数是42亿多个
和List类型不一样的是,Set集合中不允许出现重复的元素
Set集合类型还可以在服务器端进行聚合计算操作,如 unions、intersection和differences
-
sadd key value1 value2 value3..... 向set中添加数据,如果value值重复,则不会二次添加
-
smembers key 获取key中所有的成员
-
srem key member1 member2.....删除set中指定的成员
-
sismember key member 判断参数中指定的成员是否在该set中存在,1表示存在,0表示不存在
-
scard key 获取key中成员的数量
-
srandmember key count 随机获取set中的一个成员 随机获取count个成员
-
和集合相关
-
sdiff key1 key2 返回key1与key2中相差的成员 并且和key的顺序有关 返回的是差集
-
sdiffstore destination key1 key2 将key1、key2相差的成员存储在destination中
-
sinterstore destination key1 key2 将返回的交集存储在destination中
-
sunion key1 key2 返回并集
-
sunionstore destination key1 key2 将并集存储在destination中
-
sortedset类型
sortedset和set类型几乎一样,都是字符串的集合,都不允许出现重复的成员在同一个set中,区别在于
sortedset中每一个成员都会有一个分数(score)与之相关,
Redis中正是通过这个分数来为集合中每个成员进行从小到大排序
虽然sortedset中的成员必须是唯一的 ,但是分数score却是可以重复的
在sortedset集合中添加删除或者修改一个成员时速度较快
由于sortedset中的成员在集合中的位置是有序的,因此即便是访问位于集合中间的元素效率也是非常高的
-
zadd key score1 member1 score2 member2 score3 member3.....将所有的成员以及该成员的分数存放到sortedset集合中
-
zscore key member 返回执行成员中的分数
-
zcard key 获取集合中的成员数量
-
zrem key member[member....] 移除集合中指定的成员,可以删除多个成员
-
zrange key start end [withscores] 获取集合中脚标为start end的成员 [withscores] 参数返回成员包含的分数
-
zrevrange key start end [withscores] 按照分数从大到小的顺序返回索引从start end中间的元素 ,[withscores] 参数返回成员包含的分数
-
删除元素
-
zremrangebyrank key start end 按照排名顺序删除从后到前的元素
-
zremrangebyscore key start end 按照分数从小到大依次删除
-
-
zrangebyscore key min max [withscores] [limit offset count] 返回分数在[min,max]的成员并且按照分数从小到大的进行排序 [withscores] 显示分数 [limit offset count] offset 起始值 从脚标为offset的元素开始并返回count个成员信息
-
zcount key min max 获取分数在[min,max]中间的成员个数
-
zincrby key increment member 设置指定成员的增加的分数
-
zrank key member 返回成员在集合中的排名 从小到大排序 索引从0开始的
Redis持久化
redis是一个基于内存的缓存型数据库,当redis宕机或者重启时,存储在redis中的数据就会清除
我们可以将redis内存中存储的数据进行持久化,存储到硬盘上,数据就被永久性保存在文件中。
redis的持久化机制
-
RDB机制:默认方式,不配置,redis默认就使用这种机制
-
在一定的间隔时间内,检测key值的变化情况,然后进行持久化,把数据存储到硬盘上
-
编辑配置redis的RDB机制 redis.conf
-
save 900 1
-
save 300 10
-
save 60 10000
-
-
如果你修改了redis.conf 需要重启redis服务器
-
-
AOF:日志记录的方式,可以记录每一条命令的操作,可以在每一次命令操作后,进行持久化数据
-
编辑redis.conf文件
-
搜索 appendonly no(关闭) ----> yes
-
搜索 appendfsync everysec
-
appendfsync everysec 每一秒进行一次持久化数据
-
appendfsync always 每一次操作进行一次持久化数据
-
appendfsync no 不进行持久化数据
-
-
重启redis服务器
-
Java客户端连接Redis
Redis不仅可以使用命令操作,也可以使用后端开发语言进行操作 市面上主流的语言基本都支持
有很多 Java客户端,有Jedis、Redisson、Jredis等,目前企业中常用的是Jedis
开发步骤:
-
导包:导入maven坐标依赖
<!--导入redis依赖-->
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.0.1</version>
</dependency>
<!--导入redis连接池依赖-->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.3</version>
</dependency>
构建Jedis客户端对象
例如: Jedis jedis = new Jedis("192.168.68.129",6379) 主机IP地址
使用Jedis中的 API方法
代码演示:
// 练习String类型
@Test
public void test02() throws InterruptedException {
// set get
jedis.set("gender", "男");
jedis.set("age", "20");
String gender = jedis.get("gender");
String age = jedis.get("age");
System.out.println(gender);// 男
System.out.println(age);//
// 设置key的过期时间
jedis.setex("gender", 5, "女");
Thread.sleep(6000);
String gender1 = jedis.get("gender");
System.out.println(gender1);// null nil
// 增长数据
jedis.incrBy("age", 20);
String age1 = jedis.get("age");
System.out.println("--------------------------------");
System.out.println("增加数值之后:"+age1);
// 设置多个key/value值
System.out.println("=======================================");
jedis.mset("address","郑州","course","Java","num","43","birthday","2020-01-01");
List<String> mget = jedis.mget("address", "course", "num", "birthday");
for (String s : mget) {
System.out.println(s);
}
// 删除某个元素
jedis.del("address");
System.out.println("==========================");
List<String> mget2 = jedis.mget("address", "course", "num", "birthday");
for (String s : mget2) {
System.out.println(s);
}
}
// 练习Hash类型 map数据类型格式
@Test
public void test03() {
// hset hget hgetall
jedis.hset("people1", "username", "小孙");
jedis.hset("people2", "username", "小王");
jedis.hset("people1", "age", "20");
jedis.hset("people1", "gender", "男");
String username = jedis.hget("people1", "username");
String age = jedis.hget("people1", "age");
String gender = jedis.hget("people1", "gender");
System.out.println("姓名:" + username + "\n" + "年龄:" + age + "\n" + "性别:" + gender);
System.out.println("===============================================");
String username2 = jedis.hget("people2", "username");
System.out.println(username2);
// 获取Hash的所有的map中的数据
Map<String, String> people1 = jedis.hgetAll("people1");
System.out.println("==========================================");
System.out.println(people1);// 重写toString
//遍历map
// 删除
jedis.hdel("people2", "username");
// h获取
Map<String, String> people2 = jedis.hgetAll("people2");
System.out.println("====================================");
System.out.println(people2);// {}
System.out.println("*********************************************");
// 获取所有的value值
List<String> people11 = jedis.hvals("people1");
System.out.println(people11);
// 获取所有的key值 存放在Set集合中
Set<String> people12 = jedis.hkeys("people1");
}
// 练习 list类型 linkedList数据类型格式 支持重复元素
@Test
public void test04() {
// lpush 头部添加元素
// rpush 尾部添加元素
// lpop 头部删除元素
// rpop 尾部删除元素
// lrange start end 获取 [start,end] 区间范围的值
// linsert
// 获取长度 llen("key")
// 获取指定索引的数据 lrange("key",0,1)
// 按照索引修改值 lset("key","0","替换的值")
jedis.lpush("country", "美国","英国","意大利","中国");
jedis.lset("country", 3, "中国001");
List<String> country = jedis.lrange("country", 0, 3);
System.out.println(country);
// 删除区间以外的值 jedis.ltrim("key",start,end) [中国, 意大利, 英国, 中国001]
jedis.ltrim("country", 1, 2);
System.out.println("-------------------------------------");
List<String> country2 = jedis.lrange("country", 0, 3);
System.out.println("删除之后的值为:" +country2);
// 如果内容为数字可以进行排序,不会影响原来的顺序
jedis.lpush("agess", "20","30","10","50","100");
List<String> ages1 = jedis.sort("agess");// [10, 20, 30, 50, 100]
System.out.println(ages1);
System.out.println("******************************");
List<String> ages = jedis.lrange("agess", 0, 4);
System.out.println("排序后的ages值为:" + ages);// [100, 50, 10, 30, 20]
}