1:为什么要使用redis?
答:随着大数据时代的来临,1.电商网站的数据库压力越来越大 2.多台服务器之间,需要做到同步(例如:游戏的分区等)3.传统锁在多台服务器间失效
2.1关于关系型数据库和NOSQL数据库(键值对存储的数据库)
关系型数据库是基于关系表的数据库,最终将数据持久化到磁盘中,而nosql数据库是基于特殊的结构,并将数据存储到内存的数据库。从性能上而言,nosql数据库要优于关系型数据库(如:mysql),从安全性上而言关系型数据库要优于nosql数据库,所以在实际开发中一个项目中nosql和关系型数据库会一起使用,达到性能和安全性的双保证。
NOSQL产品:redis,mongodb,memcached...
Redis就是一款NoSQL,NoSQL:非关系型数据库,Not Only SQL.
Key-Value:Redis ...
文档型:ElasticSearch,Solr,Mongodb ...
面向列:Hbase,Cassandra ...
图形化:Neo4j ...
除了关系型数据库都是非关系型数据库
NoSQL只是一种概念,泛指非关系型数据库,和关系型数据库做一个区分
2.2 Redis介绍
Redis(Remote Dictionary Server) 即远程字典服务,Redis是由C语音去编写,Redis是一款基于Key-Value的NoSQL,而且Redis是基于内存存储数据的,Redis还提供了多种持久化的机制,性能可以达到110000/s读取数据以及81000/s写入数据,Redis还提供了主从,烧饼以及集权的搭建方式,可以更方便的横向扩展及垂直扩展。
3.1安装Redis
官网:Redis
中文网:Redis中文网
3.2 安装步骤
1.把下载好的redis-6.2.6.tar.gz安装包拷贝到当前虚拟机root目录下,解压到/usr/local下
[root@localhost ~]#tar -zxvf redis-6.26.tar.gz -C /user/local
2.配置C环境
[root@localhost ~]#yum install gcc-c++
3.进入redis-6.2.6目录 使用make命令编译redis(若报错,先make distclean,再make)
[root@localhost redis-6.2.6]#make
4.使用make PREFIX=/usr/local/redis-6.2.6 install命令安装(安装后出现bin)
[root@localhost redis-6.2.6]#make PREFIX=/usr/local/redis-6.2.6 install
5.启动redis服务端(前台启动)
[root@localhost redis-6.2.6]#cd bin
[root@localhost bin]#./redis-server
[root@localhost bin]# cd ../
[root@localhost redis-6.2.6]#cp redis.conf bin/redis.conf
切换到bin目录下,修改redis.conf文件
[root@localhost redis-6.2.6]#cd bin
[root@localhost bin] #vim redis.conf
3.将redis.conf文件的daemonize的值从no修改成yes表示后台启动
启动redis服务端(后台启动)
[root@localhost bin]# ./redis-server redis.conf
查看是否启动成功
[root@localhost bin]#ps -ef|grep redis
启动客户端
[root@localhost bin]# ./redis-cli
存取数据进行测试
127.0.0.1:6379>set name jack
127.0.0.1:6379>get name
"jack"
3.3 Redis的配置文件
这个地方重要配置有两个:1.daemonize 设置no 2.port 端口6379
简单测试:100个并发,十万个请求,单机测试
[root@localhost bin]#./redis-benchmark -h 127.0.0.1 -p 6379 -c 100 -n 100000
4.Redis的数据类型
常用的5中数据结构:
key-string: 一个key对应一个值
key-hash:一个key对应一个Map
key-list:一个key对应一个列表
key-set:一个key对应一个集合
key-zset:一个key对应一个有序的集合
另外三种数据结构:
HyperLogLog:计算近似值的;
GEO:地理位置;
BIT:一般存储的也是一个字符串,存储的是一个byte[]。
redis是一种高级的key-value的存储系统,其中的key是字符串类型,尽可能满足如下几点:
1.key不要太长,最好不要操作1024个字节,这不仅会小号内存还会降低查找效率
2.key不要太短,如果太短会降低key的可读性
3.在项目中,key最好有一个统一的命名规范(根据企业的需求)
value最常用的五种数据类型:
1.字符串(String):最常用的,一般用于存储一个值
2.列表(List):使用list结构实现栈和队列结构
3.集合(Set):交集,差集和并集的操作
4.有序集合(sorted set):排行榜,积分存储登操作
5.哈希(Hash):存储一个对象数据的
5.1字符串(String)
set key value:设定key持有指定的字符串value,如果该key存在则进行覆盖操作,总是返回"OK"
get key:获取key的value 如果与该key关联的value不是String类型,redis将返回错误信息,因为get命令只能用于获取String value,如果该key部存在,返回null
getset key value:先获取该key的值,然后在设置该key的值。
incr key:将指定的key的value原子性的递增1.如果该key不存在,其初始值为0,在incr之后其值位1.如果value的值不能转成整形,如hello,该操作将执行失败并返回相应的错误信息。
decr key:将指定的key的value原子性的递增1.如果该key不存在,其初始值为0,在incr之后其值为-1.如果value的值不能转成整型,如hello,该操作将执行失败并返回相应的错误信息。
incrby key increment:将执行的key的value原子性增加increment,如果该key不存在,其初始值为0,在incrbu之后,改制为increment。如果该值不能转成整型,如hello则失败并返回错误信息。
decrby key decrement:将指定的key的value原子性减少decrement~~~
append key value:如果该key存在,则在原有的value后追加该值,如果该key不存在,则重新创建一个key/value.
setex key seconds value:设置key以及对应的value,还可以设置国企时间
setnx key value:当key不存在时,设置对应的value,当key存在时,不做任何操作
使用场景如下:
1.简单的缓存存储(最常用)
2.消息的失效性(过期时间的设置)
3.分布式锁的实现(redisson)
5.2列表
lpush list1 value1 value2 ...:在指定的key关联的list的头部插入所有的values,如果该key不存在,该命令在插入的之前创建一个与该key关联的空链表,之后再向该链表的头部插入数据,插入成功,返回元素的个数。
rpush list value1 value2 ...:在该list的尾部添加元素。
lrange list start end:获取链表中从start到end的元素的值,start、end可为负数 一般取0 -1.(-1表示链表尾部的元素,-2则表示倒数第二个,一次类推...)
lrem key count value:删除count个值为value的元素,如果count大于0,从头到尾遍历并删除count个值为value的元素,如果count小于0,则从尾到头遍历并删除,如果count = 0,则删除链表中所有的等于value的元素。
linsert key before|after pivot value:在pivot元素前或者后插入value这个元素
使用场景如下:
用户的id作为key,发送的消息作为value。例如:朋友圈的发布,微博发布,公众号发布...
5.3 集合(set,不允许出现重复的元素)
5.3.1 单个集合的命令
sadd key value1 value2...:向set中添加数据,如果该key的值已有则不会重复添加。
smembers key:获取set中所有的成员。
scard key:获取set中成员的梳理。
sismember key member:判断参数中指定的成员是否在该set中,1表示存在,0表示不存在或者该key本身就不存在
删除set中menb1 menb2:srem key menb1 menb2 ...
随机删除set集合成员:srandmember set1
5.3.2 两个集合的差集 交集 并集
求差集:sdiff set1 set2(与key的顺序有关,多的集合在前)
返回差集并存储:sdiffstore setdiff set1 set2 (将set1减去set2的集合存在setdiff上)
求交集:sinter setdiff set1 set2
求交集并存储:sinterstore setdiff set1 set2
求交集:sunion set1 set2
求交集并返回:sunionstore set3 set1 set2
使用场景如下:
抽奖活动:1.把所有的用户统一存入set集合中
2.查看所有的抽奖人数
3.随机抽取指定得奖人数并从集合中删除
实现:1.sadd award user1,user2,user3 ...
2.smembers award
3.spop awad[count]
or 微信点赞,微博收藏
1.点赞,常见集合并加入对应的用户
2.取消点赞,从集合中删除对应的用户
3.检查用户看是否点过赞
4.获取点赞的用户列表
5.获取点赞用户量
实现:
1.sadd like user1,user2,user3 ...
2.srem like user1
3.sismember like user1
4.smembers like
5.scard like
可能认识的人推荐:
1.两个集合取交集
实现:
1.sinter list1,list2 ...
2.sinterstore list list1,list2
5.4 有序集合(sorted set)
zadd set1 score1 zhangsan score2 lisi ...将成员的分数存到sorted-set中。
遍历集合:zrange set3 0 -1 withscores
集合排序:zrangebyscore set3 min max withscores:
求成员的位置:zrank key member
移动指定成员:zrem key member[member ...]
返回指定成员的分数:zscore key member:
使用场景如下:
排行榜实现
1.对播放的视频,分数自增1
2.展示排行前十的视频
实现:
1.zincrby videos 1 video1id
2.zrevrangebyscore videos 100 0 withscores limit 0 9 (zrevrangebyscore从大到小排列顺序)
5.5 哈希(Hash)
添加:hset key field value
获取:hgetall key
返回指定值:hget key field
设置key中的多个value:hmset key fields:
获取key中的多个filed的值:hmget key fileds:
判断指定的key中的字段是否存在:hexists key field
获取key所包含的字段的数量:hlen key
设置key中数值的增加:hincrby key field increment
使用场景如下:
购物车场景:
1.用户的id作为key
2.商品的id作为field(属性)
3.商品的数量作为value(属性值)
购物车操作:
1.用户添加购物车:hset cart:1001 200 1(id为1001的用户添加了一个id为200的商品,数量为1个)
2.增加对应的商品数量:hincrby cart:1001 200 1
3.查询商品总数:hlen cart:1001
4.删除该用户的某个商品:hdel cart:1001 200
5.查询该用户的购物车信息:hgetall cart:1001
5.6 通用操作
keys patten:获取所有与patten匹配的key,*表示任意字符,?表示一个字符
del key1 key2...:删除指定的key
exists key:判断该key是否存在,1表示存在,0 表示不存在
rename key newkey:为当前key重命名
expire key second:为当前的key设置过期时间(单位:秒)
ttl key:查看当前key剩余过期时间
type key:查看当前key的类型
flushall:删除所有的key
6.Jedis的使用
jedis就是集成了redis的一些命令操作,封装了redis的java客户端。提供了连接池管理。一般不直接使用jedis,而是在其上在封装一层,作为业务的使用。
1.修改/usr/local/redis-5.0.4/bin目录下的redis.conf配置文件,然后启动redis服务端
注释掉:127.0.0.1 然后关闭保护模式
如需设置密码,可以使用一下两种方式:
方式一:通过修改redis.conf文件,设置Redis的密码校验
requirepass 密码
方拾贰:在不修改redis.conf文件的前提下,在第一次连接Redis时,输入命令:Config set requirepass 密码
后续连接redis客户端的时候,需要先AUTH做一下校验
127.0.0.1:6379>auth 密码
2.创建Maven工程,导入依赖
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.1.0</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.58</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
3.编写实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Integer uid;
private String username;
private String password;
}
4.编写测试类
package com.qf.jedis;
import org.junit.Test;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import redis.clients.jedis.JedisPoolConfig;
public class JedisDemo {
// 通过java程序访问redis数据库
// 获得单一的jedis对象操作数据库
@Test
public void test1() {
//获得连接对象
Jedis jedis = new Jedis("192.168.153.132", 6379);
//认证密码
//jedis.auth("root");
//获得之前redis中存储的数据
String name = jedis.get("name");
System.out.println(name);
//存储数据
jedis.set("password", "123");
System.out.println(jedis.get("password"));
//关闭
jedis.close();
}
//通过jedis的pool获得jedis连接对象
@Test
public void test2() {
// 创建池子的配置对象
JedisPoolConfig poolConfig = new JedisPoolConfig();
poolConfig.setMaxIdle(30);// 最大闲置个数
poolConfig.setMinIdle(10);// 最小闲置个数
poolConfig.setMaxTotal(50);// 最大连接数
// 创建一个redis的连接池
JedisPool pool = new JedisPool(poolConfig, "192.168.153.132", 6379);
// 从池子中获取redis的连接资源
Jedis jedisPoolResource= pool.getResource();
// 创建User类进行存储
User user = new User(1001, "李四", "123");
// 将对象转换成json存储
jedisPoolResource.set("user", JSON.toJSONString(user));
String db_user = jedisPoolResource.get("user");
// 返回json数据
System.out.println(db_user);
// 返回User类型
System.out.println(JSON.parseObject(db_user,User.class));
// 关闭资源
jedis.close();
pool.close();
}
}
7.Redis中的事务
Redis中的事务和MySQL中的事务有本质的区别,Redis中的事务是一个单独的隔离操作,事务中所有的命令都会序列化,按顺序执行,事务在执行的过程中,不会被其他客户端发来的命令所打断,因为Redis服务端是个单线程的架构,不同的Client虽然看似可以同事保持连接,但发出去的命令是序列化执行的,这在通常的数据库理论下是最高级别的隔离。
Redis中的事务的作用就是串联多个命令,防止别的命令插队。
常用命令:multi、exec discard watch unwatch
当输入multi命令时,之后输入的命令都会被放在队列中,但不会执行,直到输入exec后,Redis会将队列中的命令依次执行,discard用来撤销exec之前被暂存的命令,并不是回滚。
watch/untatch
在执行multi之前,先执行watch key1 ,watch 提供的乐观锁功能(初始时一个版本号,exec之后会更新当前版本号),在你exec的那一刻,如果被watch的键发生过改动,则multi到exec之间的指令全部不执行。
watch表示监控,相当于枷锁,但在执行完exec时就会解锁。
unwatch取消所有锁。
Redis中的事务特性总结
1.单独的隔离操作
事务中的所有的命令都会序列化,然后按照顺序执行,在执行过程中,不会被其他的客户端发送的命令打断。
2.没有隔离界别的概念
队列中的命令没有被提交之前都不会执行。
3.不能保证原子性
Redis同一个事务中如果有一跳命令执行失败,其后的命令仍然会被执行,不会回滚
8.redis中的持久化
Redis有两种持久化的方式:RDB和AOF
1.RDB(Redis DataBase)
将内存中的数据以快照的方式写入磁盘中,在redis.conf文件中,我们可以找到如下配置:
save 900 1
save 300 10
save 60 10000
配置含义:
900秒内,如果超过1个key被修改,则发起快照保存
300秒内,如果超过10个key被修改,则发起快照保存
60秒内,如果1万个key被修改,则发起快照保存
RDB方式存储的数据会在
dump.rdb文件中(在哪个目录启动Redis服务端,该文件就会在对应目录下生成),该文件不能查看,如需备份,对Redis操作完成之后,只需拷贝该文件即可(Redis服务端启东市会自动加载该文件)
2.AOF (Append of file)
AOF默认不开启,需要手动开启,同样是在redis.conf文件中开启,如下:
配置文件中的appendonly修改为yes,开启AOF持久化,开启后,启动redis服务端,发现多了一个appendonly.aof文件,之后的任何操作都会被保存在appendonly.aof文件中,可以进行查看,Redis启动时会将appendonly.aof文件中的内容执行一遍。
如果AOF和RDB同时开启,系统会默认读取AOF的数据。
3.总结
RDB优点与缺点:
优点:如果要进行大规模数据的回复,RDB的方式要比AOF方式恢复速度快。
RDB是一个非常紧凑(compact)的文件,它保存了某个时间的数据集,非常适合用作备份,同时也非常适合用作灾难性恢复,它只有一个文件,内容紧凑,通过备份袁文件到本级外的其他主机上,一旦本机发生宕机,就能将备份文件复制到Redis安装目录下,通过启动服务就能完成数据的恢复。
缺点:RDB这种持久化方式不太适应对数据完整性要求严格的情况,因为,尽管我们可以用修改快照实现持久化的频率,但是要持久化的数据是一段时间内的整个数据集的状态,如果在还没有触发快照时,本机就宕机了,那么对数据库所做的写入操作就随之小时了,并没有持久化到本地dump.rdb文件中
AOF优点与缺点
优点:AOF有着多种持久化策略:
appendfsync always:每修改同步,每一次发生数据变更都会持久化到磁盘上,性能较差,但数据完成性好
appendfsync everysec:每秒同步,每秒内记录操作,异步操作,如果一秒内宕机,有数据丢失
appendfsync no:不同步。
AOF文集是一个只进行追加操作的日志文件,对文件写入不需要进行seek,及时在追加的过程中,写入了不完成的命令,可以使用Redis-check-aof工具就可以修复这种问题
Redis 可以在AOF文件变的过大时,会自动地在后台对AOF进行重写:重写后的新的AOF文件包含了回复当前数据集所需要的最小命令集合,整个重写操作是绝对安全的,因为redis在创建AOF文件的过程中,会继续将命令追加到现有的AOF文件中,及时在重写的过程中发生宕机,现有的AOF文件也不会丢失。一旦信AOF文件创建完毕,Redis就会从旧的AOF文件切换到新的AOF文件,并对新的AOF文件进行追加操作。
缺点:对于相同的数据集来说,AOF文件要比RDB文件大。
根据所使用的持久化策略来说,AOF的速度要鳗鱼RDB。一般情况下,每秒同步策略小郭较好,不适用同步策略的情况下,AOF与RDB速度一样快。
9 redis中的消息订阅与发布
Redis中默认有16个库,可以在不同的库中存储数据,默认使用0号库存储数据,使用select 0-15可以选择不同的库。