特点
单线程+多路IO复用技术
键操作
常用数据类型 string
数据结构
常用数据类型 list
数据结构
常见数据类型 set
数据结构
常见数据类型 hash
常见数据结构Zset
数据结构
Redis 发送和订阅(一种消息的通讯模式)
发布订阅命令
新数据类型
Bitmaps
操作命令
bitop
bitmaps和set比较
HyperLogLog
命令
Geospatial
命令
Jedis操作redis6
使用java操作redis(注意修改redis配置文件)
jedis实战
springboot整合redis
添加依赖
配置redis
添加redis配置类
事务-基本操作
定义
事务错误处理
组队中有语法错误,执行时 都会回滚
组队中无语法错误,但有逻辑错误,有逻辑错误的那一条会失败,其他的正常执行
事务冲突
悲观锁
乐观锁 (redis使用的机制)
场景:抢票
watch()
watch使用实例
假设有一个计数器,需要多个客户端同时对其进行读取和修改。如果不采取任何措施,可能会导致并发修改问题。例如,假设计数器的当前值为10,现在有三个客户端 A、B 和 C,都要对计数器进行加1操作:
- 客户端 A 从 Redis 读取计数器的当前值,得到 10。
- 在客户端 A 对计数器进行修改之前,客户端 B 也读取了计数器的值,得到 10。
- 客户端 A 将计数器的值加1,得到 11,并将结果写回 Redis。
- 在客户端 A 完成修改之后,客户端 C 也读取了计数器的值,得到 11。
- 客户端 B 将计数器的值加1,得到 11,并将结果写回 Redis。
- 最后,客户端 C 也将计数器的值加1,得到 12,并将结果写回 Redis。
在这种情况下,计数器的值最终被增加了 2,而不是 3。这是因为客户端 B 和客户端 C 都读取了同一个初始值,并都将其增加了1,但是只有客户端 C 的结果得以保留。这样就会导致数据不一致的问题。
为了避免这种情况,可以使用 Redis 的事务机制和
watch()
方法来解决。首先,客户端 A 调用watch()
方法,以监视计数器的键。然后,客户端 A 开始一个事务,并将计数器的值读取到本地变量中。接着,客户端 A 将计数器的值加1,并提交这个事务。如果在此期间有其他客户端修改了计数器的值,watch()
方法就会检测到这种变化,事务将被中止。在这种情况下,客户端 A 可以通过重试事务来确保计数器的值最终增加了3,而不是2。 客户端 B 和客户端 C 可以以相同的方式访问计数器,使用事务和watch()
方法来确保数据一致性。这样就可以避免并发修改问题,确保 Redis 中的数据在事务执行期间处于一致的状态。
watch的监控原理
在 Redis 中,每个键都有一个关联的版本号(version number)。当客户端调用 watch() 方法时,Redis 会记录被监视键的版本号。在事务执行期间,如果有其他客户端修改了被监视键的值,Redis 将会增加该键的版本号。当事务执行 exec() 方法时,Redis 会检查被监视键的版本号是否发生变化。如果版本号发生了变化,说明被监视键已经被其他客户端修改,事务将被中止,所有对被监视键的修改都会被回滚。 具体来说,当客户端调用 watch() 方法时,Redis 会为每个被监视键创建一个 WatchedKey 对象,并将其添加到客户端的监视列表中。WatchedKey 对象包含了键的名称和版本号。在执行事务期间,Redis 会记录所有被修改的键及其新值,但不会立即更新这些键的值。当事务执行 exec() 方法时,Redis 会检查每个被监视键的版本号是否与事务开始时记录的版本号相同。如果某个被监视键的版本号发生了变化,说明被监视键已经被其他客户端修改,Redis 将会中止事务,所有对被监视键的修改都会被回滚。 如果事务执行成功(即没有被其他客户端修改过被监视键的值),Redis 会将所有被修改的键的值更新为事务执行期间记录的新值,并将版本号增加1。 总之,watch() 方法实现了一种乐观锁机制,即在执行事务之前,先记录被监视键的版本号,如果事务执行期间发现被监视键的版本号发生了变化,就说明其他客户端已经对该键进行了修改,事务就会被中止,从而避免了并发修改导致的问题。
事务的三特性
事务案例-秒杀
- 超卖问题(并发问题)---使用乐观锁解决
- 连接超时问题------使用连接池
数据库遗留问题
解决方法使用lua脚本
redis 持久化操作-RDB
redis是数据在内存中,将内存的数据写入硬盘就是持久化的过程
rdb的配置文件
redis默认会进行持久化操作
优缺点
rdb备份
挂掉的redis根据rdb恢复数据
redis 持久化操作-AOF(Append only file)
AOF默认不开启
aof文件损坏修复
aof配置
压缩操作
aof持久化流程
主从复制
主从复制-----搭建一主多从
主从复制-复制原理
常见的3个问题
一主二仆
- 主机死了 从机依然认主机为主
- 从机死了 再次重启就忘掉了之前的主从关系
主从复制原理
薪火相传
减轻master写压力,去中心化降低风险
反客为主 手动
java代码实现 主从模式
public class RedisMasterSlaveReplication {
public static void main(String[] args) {
// 创建 Jedis 连接到主服务器
Jedis master = new Jedis("localhost", 6379);
// 创建 Jedis 连接到从服务器
Jedis slave = new Jedis("localhost", 6380);
// 设置从服务器复制主服务器的数据
slave.slaveof("localhost", 6379);
// 测试复制是否成功
master.set("test_key", "Hello, Redis!");
System.out.println("Value from master: " + master.get("test_key"));
// 稍等片刻,以便从服务器将数据复制到自身
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("Value from slave: " + slave.get("test_key"));
// 关闭 Jedis 连接
master.close();
slave.close();
}
}
哨兵模式
哨兵的配置模式
启动哨兵
java代码实现
import redis.clients.jedis.HostAndPort;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisSentinelPool;
import java.util.HashSet;
import java.util.Set;
public class RedisSentinelMode {
public static void main(String[] args) {
// 哨兵地址集合
Set<String> sentinels = new HashSet<>();
sentinels.add("localhost:26379"); // 哨兵1地址
// 创建 JedisSentinelPool 对象,连接到哨兵
// "mymaster" 是哨兵配置文件中主服务器的名称
JedisSentinelPool sentinelPool = new JedisSentinelPool("mymaster", sentinels);
// 从 JedisSentinelPool 获取 Jedis 对象
try (Jedis jedis = sentinelPool.getResource()) {
// 使用 Jedis 对象进行操作
jedis.set("test_key", "Hello, Redis Sentinel!");
System.out.println("Value: " + jedis.get("test_key"));
}
// 关闭 JedisSentinelPool
sentinelPool.close();
}
}
redis集群
主机代理方式
去中心化集群
什么是集群
搭建集群
配置文件
合体为集群
连接集群服务器
插槽slot(主要作用平均分担压力)
故障恢复
集群的jedis开发
应用问题----缓存穿透
黑客攻击
应用问题----缓存击透
内存雪崩
分布式锁(设置锁和过期时间)