redis
1、什么是NOSQL?
NoSQL ( Not only sql ) 是对不同于传统的关系数据库的数据库管理系统的统称,即广义地来说可以把所有不是关系型数据库的数据库统称为NotSQL。
2、nosql和rdbms的区别
NoSQL的特点:(Not Only SQL ) 非关系型数据库
· 工具:Redis、Hbase、MongoDB
· 应用:一般用于高并发高性能场景下的数据缓存或者数据存储。
· 特点:读写速度特别快,并发量非常高。相对而言,不如RDBMS稳定,对事务性的支持不太友好。
· 开发:每种NoSQL都有自己命令语法
RDBMS的特点:关系型数据库管理系统
· 工具:MySQL、Oracle、SQL Server
· 应用:业务性数据存储系统
· 特点:体现数据之间的关系,支持事务,保证业务网完整性和稳定性,小数据量的性能也比较好。
3、什么是redis
Redis是一种开源的NoSQL内存数据库,用于高性能的数据存储和访问。Redis支持多种数据类型,包括字符串、哈希、列表、集合和有序集合,并且支持分布式存储和操作。Redis的特点包括快速、高可用和易扩展等,适用于各种引用场景。
4、如何安装redis
(1)安装redis前,需要先安装c语言的插件
yum install gcc-c++
(2)下载redis软件
(3)把redis压缩包上传到linux指定目录下

(4)解压redis
tar -zxvf redis-7.2.0.tar.gz
(5) 进入解压目录 并编译源码
make
(6) 安装redis---帮你安装配置环境变量
make install
(7) 启动redis服务
redis-server redis.conf
(8) 客户端连接redis
redis-cli -h【连接redis服务的ip】-p【连接redis的端口号】
5、redis.conf配置
(1)配置redis后台启动:

(2)修改端口号
(3)查看进程端口号
ps -ef | grep redis

(4)关闭进程
kill -9 进程号
6、安装redis图形化客户端软件
等价于:mysql中的navicat. 可以通过图形化对redis进程操作。

修改redis允许远程连接。
(1)设置允许所有的ip连接该redis
(2)设置是否开启保护模式-----yes开启 no表示关闭

(3)默认redis提供了16个库。如果想修改库的个数

7、redis中常用的命令
(1)数据库的命令:
select 选择库。 ==默认为第一个库0~15

flushall ==清空所有库的内容

flushdb ==清空当前库的内容

(2)关于key的命令:
keys *:查看当前库中所有的key

del key key ...: 删除指定的key

exists key: 判断指定的key是否存在

expire key seconds: 设置指定的key的过期时间 单位秒

tll key:【ttl time to live】查看当前key的有效时间。-1表示永不过期

8、redis支持的数据类型
https://www.redis.net.cn/order/
redis中它的value类型为字符串类型,该类型最多可以存放512M的内容。
redis可以存放哪些数据库类型。---redis的value可以是哪些数据类型。

使用最多的类型为: Strings字符串类型,Lists队列类型,Sets集合类型,Hashes哈希类型,SortedSet 有序集合类型。
9、字符串类型相关的命令
(1) set key value: ==存储字符串类型的数据。这里的key不允许重复


(2) get key: ==根据key获取对应的value值

(3) mset key value key value .....: ==存储多个key-value值


(4) setnx key value: ==如果指定的key存在,则不存入,如果不存在则存入

(5) incr key: ==为指定的key递增。只能对整形。

(6) decr key: ==为指定的key递减

(7)· decrby key number: ==为指定的key递减相应的值

10、hash的数据类型命令
表示redis中它的value类型为hash数据类型。hash类型的特点: 它的value也是一个键值对的形式。
(1) hset key field value: ==存放hash类型的数据

(2)hget key field: --获取对应field字段的值

(3)hgetall key: ==获取key对应hash数据内容

(4)hkeys key: ==获取hash中所有field字段

(5)hvals key: ==获取hash中所有的value值

11、List列表类型
它的value值为一个列表队列类型,列表中的元素允许重复。 key对应的value类型为一个列表类型。
(1)lpush key value value ......: ==从左边存放列表数据

(2)lpush key [count]: ==从左边取出元素

(3)lrange key start end: ==从左边获取指定范围的元素 -1,表示最后一个元素

12、set集合命令
redis中的value类型为set集合类型,特点:无序 且 不重复 的数据
(1)sadd key element element......: ==存放set类型的元素。

(2)smembers key: ==获取指定key对应的所有的元素

(3)srandmember key [ number ] : ==随机获取集合中一个或者多个元素

(4) sinter key key : ==求多个集合的交集
(5)spop key : ==随机移除一个或者多个元素

13、sorted set 集合命令
它和set的区别就是在添加元素时需要指定一个分数,该分数用来排序的。
(1) zadd key element score element score : ==添加有序集合

(2)zrang key start end [ withscores ]: ==从分数小到大的顺序获取集合中的元素

(3)zrevrange key start end [ withscores ]:==返回有序集中指定区间内的成员,通过索引,分数从高到底

14、redis的应用场景
· 热点数据的缓存:减少对数据库的访问频率,提供的用用程序的效率,
· 限时业务的运用:比如短信验证码
· 计数器相关问题:点赞、关注数
· 排行榜相关问题:销售量、观看量
· 分布式锁:自动锁 和 手动锁
15、redis 的持久化
(1)为什么要持久化
Redis是内存数据库,宕机后数据会消失,Redis重启后快速恢复数据,要提供持久化机制。Redis的两种持久化方式:RDB和AOF
(2)ROB持久化:每个一段时间对redis内存中的数据进行拍照存储
优点:数据恢复速度快。
缺点:可能会出现丢失最后一段时间的数据 -- 数据完整性比较差。
RDB持久化方式的触发机制有两种方式:
第一种:手动触发
save 或 bgsave 命令: ==持久化到磁盘中并且名字叫dump.rdb
save :

该命令会阻塞当前Redis服务器,执行save命令期间,Redis 不能处理其他命令,直接RDB工程完成为止。执行完成时候如果存在老的RDB文件,就把新的替代掉旧的。我们的客户端可能都是几万或者是几十万,这种方式显然不可取。
持久化到磁盘中并且名字叫dump.rdb :
bgsave:
执行该命令时,redis会在后台异步进行快照操作,快照同时会可以响应客户端请求。

第二种:自动触发 --修改redis的配置文件【 底层是用的还是bgsave 】

(3)AOF持久化
AOF (Append Only File)持久化默认是关闭的,通过将redis.conf中将appendonly no,修改为appendonly yes来开启AOF持久化功能,如果服务器开始了AOF持久化功能,服务器会优先使用AOF文件来还原数据库状态。只有在AOF持久化功能处于关闭状态时,服务器才会使用RDB文件来还原数库状态。
优点:数据完整性好
缺点:数据恢复慢
默认redis没有开启aof模式。如果需要开启需要修改配置文件

16、redis集群模式
(1)主从模式

搭建主从模式:原则配从不配主。
需要准备三台redis服务。---两台从节点 一台为主节点。 我们为了操作方便我们就在一台虚拟机模拟主从集群模式。只需要让三台redis服务的端口号不同即可。
第一台--主机:

第二台--从机:

连接主机:

第三台--从机:

连接主机:

通过:info replication 查询主机


通过:info replication 查询从机

(2) 哨兵模式
· 主从切换技术的方法是:当主服务器宕机后,需要手动把一台从服务器切换为主服务器,这就需要人工干预,费时费力,还会造成一段时间类服务不可用。这不是一种推荐的方式,更多时候,我们优先考虑哨兵模式。Redis从2.8开始正式提供了Sentinel(哨兵)架构来决解这个问题。
· 哨兵(sentinel)是一个分布式系统,用于对主从结构中的每台服务器进行监控,当出现故障时通过投票机制选择新的master并将所有slave连接到新的master。
哨兵的作用:
· 监控
不断的检查master和slave是否正常运行
master存活检测、master与slave运行情况检测
· 通知
当被监控的服务器出现问题时,向其他( 哨兵间、客户端) 发送通知
· 自动故障转移
断开master与slave连续,选取一个slave作为master,将其他slave链接到新的master,并告知客户端新的的服务器地址
· 哨兵也是一台redis服务器,只是不提供数据服务器
· 通常哨兵配置数量为单数



启动哨兵: redis-sentinel sentinel.conf
(
分片集群它是解决我们上面哨兵模式存在的问题。他们只有一个主节点,如果写操作频率过高,那么就会导致主节点宕机问题。
分片集群结构图:
分槽的原理:
Redis 集群中内置了 16384 个哈希槽,当需要在 Redis 集群中放置一个 key-value时,redis 先对 key 使用 crc16 算法算出一个结果,然后把结果对 16384 求余数,这样每个 key 都会对应一个编号在 0-16383 之间的哈希槽,redis 会根据节点数量大致均等的将哈希槽映射到不同的节点。
当你往Redis Cluster中加入一个Key时,会根据crc16(key) mod 16384计算这个key应该分布到哪个hash slot中,一个hash slot中会有很多key和value。你可以理解成表的分区,使用单节点时的redis时只有一个表,所有的key都放在这个表里;改用Redis Cluster以后会自动为你生成16384个分区表,你insert数据时会根据上面的简单算法来决定你的key应该存在哪个分区,每个分区里有很多key。
搭建redis分片集群:
准备6台redis服务: 3台主节点和3台从节点。[7001 7002 7003 7004 7005 7006]
修改redis集群中6台配置文件的内容:
1,修改端口号:
2. 修改rdb文件的名称
3. 必须开启aof模式并修改aof文件的名称
4. 开启redis集群模式 cluster-enabled yes
5. 修改集群文件名 cluster-config-file nodes-7001.conf
6. 设置允许任意ip访问。bind * -::*

根据配置文件启动6台redis服务

为上面6台redis设置主从关系并分配槽:
redis-cli --cluster create --cluster-replicas 1 ip:7001 ip:7002 ip:7003 ip:7004 ip:7005 ip:7006

启动redis客户端 -- redis-cli -c -h 192.168.223.158 -p 7001
测试数据:

17、java连接redis
jedis可以帮你完成java和redis之间的连接,专业易用的一个客户端。
(1)引入jedis依赖
<dependencies>
<dependency>
<groupId>redis.clients</groupId>
<artifactId>jedis</artifactId>
<version>3.6.0</version>
</dependency>
</dependencies>
(2)编写代码
public class Test01 {
public static void main(String[] args) {
//1.创建连接对象
Jedis jedis=new Jedis("192.168.223.158",6379);
//2.使用jedis来对我们的redis服务进行操作了。Jedis对象中对每个redis命令封装了对应的方法。
//对key的操作命令
Set<String> keys = jedis.keys("*");
System.out.println("所有的key:"+keys);
jedis.expire("k1",20L);
Long k2 = jedis.del("k2");
System.out.println("是否删除成功:"+k2);
//关于字符串类型的操作。value为字符串。
jedis.set("k4","k4就是香");
jedis.setnx("k4","k4真的想骂");
String va = jedis.get("k4");
System.out.println("k4对应的值:"+va);
jedis.setex("k5",20L,"设置一个过期的value");
//关于hash类型的操作
Map<String,String> map=new HashMap<String,String>();
map.put("name","张三");
map.put("age","25");
map.put("address","北京");
jedis.hset("k6",map);
System.out.println(jedis.hget("k6", "name"));
//关于list列表类型
jedis.lpush("k7","张三","李四","王五","赵六");
List<String> list = jedis.lrange("k7", 0, -1);
System.out.println(list);
//关于set和sortset省略
jedis.close();
}
}
(3)
public class Test02 {
public static void main(String[] args) {
Set<HostAndPort> set=new HashSet<HostAndPort>();
set.add(new HostAndPort("192.168.223.158",7001));
set.add(new HostAndPort("192.168.223.158",7002));
set.add(new HostAndPort("192.168.223.158",7003));
set.add(new HostAndPort("192.168.223.158",7004));
set.add(new HostAndPort("192.168.223.158",7005));
set.add(new HostAndPort("192.168.223.158",7006));
//创建一个Jedis集群对象---需要传入redis集群服务的地址信息
JedisCluster jedisCluster=new JedisCluster(set);
jedisCluster.set("k66","v66");
System.out.println(jedisCluster.get("k66"));
jedisCluster.close();
}
}
(4)
springboot在整合redis时会自动封装了两个类:
RedisTemplate和StringRedisTemplate. StringRedisTemplate它是RedisTemplate的子类,
StringRedisTemplate它里面存储的key和value都是字符串类型。
(5)引入redis启动依赖jar包
会完成自动装配功能。---完成RedisTemplate的创建以及容器管理。
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
(6)修改application配置文件
# 连接单机redis
spring.redis.host=192.168.223.158
spring.redis.port=6379
(7)使用StringRedisTemplate
@Autowired
private StringRedisTemplate redisTemplate; //starter自动完成了redis的装配
@Test
void contextLoads() {
//1. 操作key
// System.out.println("=====================================关于key的操作==============================");
// Boolean flag01 = redisTemplate.delete("k1");
// System.out.println("是否删除指定key成功:"+flag01);
// Boolean k2 = redisTemplate.hasKey("k2");
// System.out.println("是否存在指定的key:"+k2);
// Set<String> keys = redisTemplate.keys("*");
// System.out.println("获取所有的key:"+keys);
//
// //2. 关于字符串的操作:默认springboot中redistemplate不能直接操作数据类型的命令。但是springboot中redisTemplate为每个数据类型都提供了一个类
// //对应的类可以操作对应的数据类型。
// //ValueOperations:专门操作字符串类型
// ValueOperations<String, String> forValue = redisTemplate.opsForValue();
// forValue.set("k88","v88");
// forValue.set("k99","v99",60, TimeUnit.SECONDS);
//
// String k88 = forValue.get("k88");
// System.out.println(k88);
// Duration duration = Duration.ofDays(5);
// forValue.setIfAbsent("k999","v999",duration);
//3. 关于hash类型的操作
HashOperations<String, Object, Object> forHash = redisTemplate.opsForHash();
forHash.put("k1","name","张三");
forHash.put("k1","age","18");
Map<String,String> map=new HashMap<>();
map.put("name","刘德华");
map.put("age","19");
map.put("address","香港");
forHash.putAll("k2",map);
Object o = forHash.get("k1", "name");
System.out.println(o);
Map<Object, Object> k2 = forHash.entries("k1");
System.out.println(k2);
//关于list set sortset的操作省略
}
(8)
@Autowired
private RedisTemplate redisTemplate;
//org.springframework.data.redis.serializer.SerializationException: 要求存入的key和value必须经过了序列化。
//思考:存入字符串类型没有报错而存入User对象报错。【因为String序列化接口了,而User类没有实现序列化接口】
//思考: 因为默认采用的是JDK序列化方式---无法看懂.---需要认为设置序列化方式
@Test
void contextLoads() {
//指定了key的序列化
redisTemplate.setKeySerializer(new StringRedisSerializer());
redisTemplate.setValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
//指定hash的key和value的序列化
redisTemplate.setHashKeySerializer(new StringRedisSerializer());
redisTemplate.setHashValueSerializer(new Jackson2JsonRedisSerializer(Object.class));
// //字符串操作
// ValueOperations valueOperations = redisTemplate.opsForValue();
// User user=new User("张三",255);
// valueOperations.set("userinfo",user);
//
// System.out.println(valueOperations.get("userinfo"));
//hash操作
HashOperations hashOperations = redisTemplate.opsForHash();
hashOperations.put("k55","name","张三");
}
如果每次使用RedisTemplate都要序列化实在优点麻烦。 人为创建RedisTemplate类对象并交于spring容器管理。
@Configuration
public class RedisConfig {
@Bean
public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory factory) {
RedisTemplate<String, Object> template = new RedisTemplate<>();
RedisSerializer<String> redisSerializer = new StringRedisSerializer();
Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
template.setConnectionFactory(factory);
//key序列化方式
template.setKeySerializer(redisSerializer);
//value序列化
template.setValueSerializer(jackson2JsonRedisSerializer);
//value hashmap序列化
template.setHashKeySerializer(redisSerializer);
template.setHashValueSerializer(jackson2JsonRedisSerializer);
return template;
}
}
18、
# 集群redis
spring.redis.cluster.nodes=192.168.223.158:7001,\
192.168.223.158:7002,\
192.168.223.158:7003,\
192.168.223.158:7004,\
192.168.223.158:7005,\
192.168.223.158:7006

浙公网安备 33010602011771号