Redis进阶

  1. 缓存雪崩 缓存穿透 缓存击穿

Redis在项目中常用作缓存来使用,主要用两大作用:

1.提升系统的性能

Redis基于内存,IO效率远高于MySql数据库

2.减少数据库压力

Redis处理很多请求,使用Redis作为缓存可以减少数据库的请求量,避免数据库因为请求过多、压力过大而导致宕机。

在这里插入图片描述
击穿问题解决案例

解决方法:使用双检锁DCL机制优化方法,通过给代码块加上synchronized锁,同步代码块的方式。再加上if else判断的方式来优化方法,解决击穿的问题,优化性能。

@Override
    public Student getStudentById(Long id) {
        //获得字符串操作对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //先查询Redis
        Student stu = (Student) ops.get(PREFIX + id);
        if(stu == null) {
            synchronized (this) {
                System.out.println("进入了同步锁");
                //先查询Redis
                stu = (Student) ops.get(PREFIX + id);
                //如果Redis缓存存在数据,就直接返回
                if (stu != null) {
                    System.out.println("Redis查到,返回" + stu);
                    return stu;
                }
                //如果Redis没有查到数据,就查询MySQL
                stu = studentMapper.selectById(id);
                //MySQL查到数据,就保存到Redis
                if (stu != null) {
                    System.out.println("MySQL查到,返回" + stu);
                    ops.set(PREFIX + id, stu);
                    return stu;
                }
                //MySQL没有数据,就返回null
                System.out.println("MySQL没有数据,就返回null");
            }
        }else {
            System.out.println("没有执行同步锁");
        }
        return stu;
    }

穿透问题

缓存空对象,空对象设置过期时间

@Override
    public Student getStudentById(Long id) {
        //获得字符串操作对象
        ValueOperations<String, Object> ops = redisTemplate.opsForValue();
        //先查询Redis,如果存在数据就不执行同步代码块,直接返回
        Student stu = (Student) ops.get(PREFIX + id);
        if(stu == null) {
            synchronized (this) {
                System.out.println("进入了同步锁");
                //先查询Redis
                stu = (Student) ops.get(PREFIX + id);
                //如果Redis缓存存在数据,就直接返回
                if (stu != null) {
                    System.out.println("Redis查到,返回" + stu);
                    return stu;
                }
                //如果Redis没有查到数据,就查询MySQL
                stu = studentMapper.selectById(id);
                //MySQL查到数据,就保存到Redis
                if (stu != null) {
                    System.out.println("MySQL查到,返回" + stu);
                    ops.set(PREFIX + id, stu);
                    return stu;
                }else {
                    //MySQL没有数据,在Redis保存空对象,设置过期时间
                    System.out.println("MySQL没有数据");
                    Student student = new Student();
                    ops.set(PREFIX + id, student,5, TimeUnit.SECONDS);
                }
            }
        }else {
            System.out.println("没有执行同步锁");
        }
        return stu;
    }

2.redis消息通知 广播
消息接收端

@Test
@DisplayName("测试Redis,消息通知")
public void test5(){
 
    // 创建 Jedis 对象连接 Redis 服务器
    try (Jedis jedis = new Jedis("localhost",6379)) {
        // 创建订阅者对象
        JedisPubSub subscriber = new JedisPubSub() {
            @Override
            public void onMessage(String channel, String message) {
                // 接收到消息时的处理逻辑
                System.out.println("Received message: " + message + " from channel: " + channel);
            }
        };
 
        // 订阅名为 "channel_name" 的频道
        jedis.subscribe(subscriber, "channel_name");
 
        // 阻塞直到接收到消息
        Thread.sleep(0);
    } catch (Exception e) {
        e.printStackTrace();
    }
}

消息发送端

@Test
@DisplayName("测试Redis,发送消息通知")
public void test6(){
    // 创建 Jedis 对象连接 Redis 服务器
    try (Jedis jedis = new Jedis("localhost",6379)) {
        // 发布消息到名为 "channel_name" 的频道
        jedis.publish("channel_name", "Hello !!!!!");
    } catch (Exception e) {
        e.printStackTrace();
    }
}

优点:

高性能: Redis 的消息通知是基于发布/订阅模式实现的,使用轻量级的事件通知机制,因此具有很高的性能和低延迟。

松耦合: 发布者和订阅者之间是解耦的,发布者只需发布消息,而订阅者可以根据需要选择性地订阅感兴趣的频道或主题,这种松耦合性使得系统更容易维护和扩展。

实时性: Redis 提供了实时性的消息传递机制,能够快速地将消息传递给所有订阅者,使得系统可以快速响应和更新。

缺点:

消息丢失: Redis 是内存数据库,当服务宕机或断电时,如果消息尚未持久化到磁盘,可能会导致消息丢失。为了解决这个问题,可以采用 Redis 的持久化机制(如 AOF 或 RDB)来避免数据丢失。

无法保证可靠性: Redis 的发布/订阅机制本身不保证消息的可靠传输。订阅者可能会因为某些原因错过一些消息,因此不能保证每个订阅者都能收到所有消息。

无法跨越网络边界: Redis 是一个内存数据库,因此在不同的网络边界之间传递消息可能会受到限制。如果要在多个网络边界之间进行消息传递,可能需要使用其他的消息队列或者消息中间件来解决跨网络通信问题。

总体来说,Redis 的消息通知机制适用于许多实时性要求高、轻量级、非关键性的消息通知场景。但在一些对消息的可靠性和持久性有较高要求的场景下,可能需要考虑其他更为健壮的消息队列系统或消息中间件。

3.redis高可用 哨兵模式 集群模式

Redis 高可用有三种主要模式:主从复制模式(Master-Slave),哨兵模式(Sentinel)和集群模式(Cluster)。它们都旨在提供高可用性和容错性,但在实现方式和应用场景上有所不同。

哨兵模式(Sentinel)
特点: 哨兵模式是一种分布式系统,用于监控 Redis 实例的健康状态,并在主服务器宕机时自动进行故障转移。

工作原理: 哨兵模式由若干哨兵进程组成,这些哨兵会监视 Redis 主服务器和从服务器的状态。当主服务器宕机或无法访问时,哨兵会选举出新的主服务器,并将从服务器提升为新的主服务器,以确保系统的高可用性。

适用场景: 适用于对数据的持久性要求较高,但对于读写速度不是特别高的应用场景。

集群模式(Cluster)
特点: 集群模式是 Redis 3.0 版本后引入的功能,用于实现分布式存储和高性能的数据访问。

工作原理: 集群模式通过将数据分片存储在多个节点上,以提供水平扩展性和负载均衡。它支持自动数据分片和节点的动态增减,每个节点负责管理一部分数据,并通过内部通信协议进行数据交换和传输。

适用场景: 适用于对于大规模数据、高性能读写都有较高要求的应用场景。

  1. 主从复制模式(Master-Slave)
    2.1 主从复制原理
    主从复制是Redis的一种基本集群模式,它通过将一个Redis节点(主节点)的数据复制到一个或多个其他Redis节点(从节点)来实现数据的冗余和备份。

主节点负责处理客户端的写操作,同时从节点会实时同步主节点的数据。客户端可以从从节点读取数据,实现读写分离,提高系统性能。
在这里插入图片描述
2.2 主从复制配置和实现
配置主节点:在主节点的redis.conf配置文件中,无需进行特殊配置,主节点默认监听所有客户端请求。

主节点默认端口号6379

port 6379
配置从节点:在从节点的redis.conf配置文件中,添加如下配置,指定主节点的地址和端口:

从节点设置端口号6380

port 6380

replicaof 主节点IP 主节点端口

replicaof 127.0.0.1 6379

或者,通过Redis命令行在从节点上执行如下命令:
redis> replicaof 127.0.0.1 6379
验证主从复制:在主节点上执行写操作,然后在从节点上进行读操作,检查数据是否一致。
2.3 主从复制的优缺点
优点:

配置简单,易于实现。
实现数据冗余,提高数据可靠性。
读写分离,提高系统性能。
缺点:

主节点故障时,需要手动切换到从节点,故障恢复时间较长。
主节点承担所有写操作,可能成为性能瓶颈。
无法实现数据分片,受单节点内存限制。
2.4 主从复制场景应用
主从复制模式适用于以下场景:

数据备份和容灾恢复:通过从节点备份主节点的数据,实现数据冗余。
读写分离:将读操作分发到从节点,减轻主节点压力,提高系统性能。
在线升级和扩展:在不影响主节点的情况下,通过增加从节点来扩展系统的读取能力。
总结:主从复制模式适合数据备份、读写分离和在线升级等场景,但在主节点故障时需要手动切换,不能自动实现故障转移。如果对高可用性要求较高,可以考虑使用哨兵模式或Cluster模式。

  1. 哨兵模式(Sentinel)
    3.1 哨兵模式原理
    哨兵模式是在主从复制基础上加入了哨兵节点,实现了自动故障转移。哨兵节点是一种特殊的Redis节点,它会监控主节点和从节点的运行状态。当主节点发生故障时,哨兵节点会自动从从节点中选举出一个新的主节点,并通知其他从节点和客户端,实现故障转移。
    在这里插入图片描述
    3.2 哨兵模式配置和实现
    配置主从复制:首先按照主从复制模式的配置方法,搭建一个主从复制集群(上面已经讲过)。
    配置哨兵节点:在哨兵节点上创建一个新的哨兵配置文件(如:sentinel.conf),并添加如下配置:

sentinel节点端口号

port 26379

sentinel monitor 被监控主节点名称 主节点IP 主节点端口 quorum

sentinel monitor mymaster 127.0.0.1 6379 2

sentinel down-after-milliseconds 被监控主节点名称 毫秒数

sentinel down-after-milliseconds mymaster 60000

sentinel failover-timeout 被监控主节点名称 毫秒数

sentinel failover-timeout mymaster 180000
其中,quorum是指触发故障转移所需的最小哨兵节点数。down-after-milliseconds表示主节点被判断为失效的时间。failover-timeout是故障转移超时时间。
为什么只配置了sentinel监控主节点,没有配置监控从节点? 因为通过主节点,就可以找到从节点。

启动哨兵节点:使用如下命令启动哨兵节点:
redis> redis-sentinel /path/to/sentinel.conf
验证哨兵模式:手动停止主节点,观察哨兵节点是否自动选举出新的主节点,并通知其他从节点和客户端。
3.3 哨兵模式的优缺点
优点:

自动故障转移,提高系统的高可用性。
具有主从复制模式的所有优点,如数据冗余和读写分离。
缺点:

配置和管理相对复杂。
依然无法实现数据分片,受单节点内存限制。
3.4 哨兵模式场景应用
哨兵模式适用于以下场景:

高可用性要求较高的场景:通过自动故障转移,确保服务的持续可用。
数据备份和容灾恢复:在主从复制的基础上,提供自动故障转移功能。
总结:哨兵模式在主从复制模式的基础上实现了自动故障转移,提高了系统的高可用性。然而,它仍然无法实现数据分片。如果需要实现数据分片和负载均衡,可以考虑使用Cluster模式。

  1. Cluster模式
    4.1 Cluster模式原理
    Cluster模式是Redis的一种高级集群模式,它通过数据分片和分布式存储实现了负载均衡和高可用性。在Cluster模式下,Redis将所有的键值对数据分散在多个节点上。每个节点负责一部分数据,称为槽位。通过对数据的分片,Cluster模式可以突破单节点的内存限制,实现更大规模的数据存储。

在这里插入图片描述
4.2 数据分片与槽位
Redis Cluster将数据分为16384个槽位,每个节点负责管理一部分槽位。当客户端向Redis Cluster发送请求时,Cluster会根据键的哈希值将请求路由到相应的节点。具体来说,Redis Cluster使用CRC16算法计算键的哈希值,然后对16384取模,得到槽位编号。

4.3 Cluster模式配置和实现
配置Redis节点:为每个节点创建一个redis.conf配置文件,并添加如下配置:

cluster节点端口号

port 7001

开启集群模式

cluster-enabled yes

节点超时时间

cluster-node-timeout 15000
像这样的配置,一共需要创建6个,我们做一个三主三从的集群。

启动Redis节点:使用如下命令启动6个节点:
redis> redis-server redis_7001.conf
创建Redis Cluster:使用Redis命令行工具执行如下命令创建Cluster:
redis> redis-cli --cluster create 127.0.0.1:7001 127.0.0.1:7002 127.0.0.1:7003 127.0.0.1:7004 127.0.0.1:7005 127.0.0.1:7006 --cluster-replicas 1
cluster-replicas 表示从节点的数量,1代表每个主节点都有一个从节点。
验证Cluster模式:向Cluster发送请求,观察请求是否正确路由到相应的节点。
4.4 Cluster模式的优缺点
优点:

数据分片,实现大规模数据存储。
负载均衡,提高系统性能。
自动故障转移,提高高可用性。
缺点:

配置和管理较复杂。
一些复杂的多键操作可能受到限制。
4.5 Cluster模式场景应用
Cluster模式适用于以下场景:

大规模数据存储:通过数据分片,突破单节点内存限制。
高性能要求场景:通过负载均衡,提高系统性能。
高可用性要求场景:通过自动故障转移,确保服务的持续可用。
总结:Cluster模式在提供高可用性的同时,实现了数据分片和负载均衡,适用于大规模数据存储和高性能要求的场景。然而,它的配置和管理相对复杂,且某些复杂的多键操作可能受到限制。

  1. 总结
    本文详细介绍了Redis的三大集群模式:主从复制、哨兵模式和Cluster模式。每种模式都有其特点和应用场景,具体如下:

主从复制模式:适用于数据备份和读写分离场景,配置简单,但在主节点故障时需要手动切换。
哨兵模式:在主从复制的基础上实现自动故障转移,提高高可用性,适用于高可用性要求较高的场景。
Cluster模式:通过数据分片和负载均衡实现大规模数据存储和高性能,适用于大规模数据存储和高性能要求场景。

4.分布式锁
1 redis 分布式锁实现原理
所谓分布式锁,应当基本如下几项核心性质:

独占性:对于同一把锁,在同一时刻只能被一个取锁方占有,这是锁最基础的一项特征
健壮性:即不能产生死锁(dead lock). 假如某个占有锁的使用方因为宕机而无法主动执行解锁动作,锁也应该能够被正常传承下去,被其他使用方所延续使用
对称性:加锁和解锁的使用方必须为同一身份. 不允许非法释放他人持有的分布式锁
高可用:当提供分布式锁服务的基础组件中存在少量节点发生故障时,应该不能影响到分布式锁服务的稳定性

在使用 redis 分布式锁时,为避免持有锁的使用方因为异常状况导致无法正常解锁,进而引发死锁问题,我们可以使用到 redis 的数据过期时间 expire 机制.

我们通常会在插入分布式锁对应的 kv 数据时设置一个过期时间 expire time,这样即便使用方在持有锁期间发生宕机无法正常解锁,锁对应的数据项也会在达到过期时间阈值后被自动删除,实现分布式锁释放的效果. 此处我们可以通过 redis 的 SETEX 指令,一气呵成地完成上锁+设置过期时间的两个步骤.

在这里插入图片描述
java实现分布式锁例子

import redis.clients.jedis.Jedis;
 
public class RedisDistributedLock {
    private Jedis jedis;
    private String lockKey;
    private String uniqueIdentifier;
    private int lockTimeout;
 
    public RedisDistributedLock(Jedis jedis, String lockKey, String uniqueIdentifier, int lockTimeout) {
        this.jedis = jedis;
        this.lockKey = lockKey;
        this.uniqueIdentifier = uniqueIdentifier;
        this.lockTimeout = lockTimeout;
    }
 
    public boolean acquireLock() {
        String result = jedis.set(lockKey, uniqueIdentifier, "NX", "EX", lockTimeout);
        return "OK".equals(result);
    }
 
    public void releaseLock() {
        // 校验并释放锁
        String script = "if redis.call('get', KEYS[1]) == ARGV[1] then return redis.call('del', KEYS[1]) else return 0 end";
        jedis.eval(script, 1, lockKey, uniqueIdentifier);
    }
 
    public static void main(String[] args) {
        String redisHost = "localhost";
        int redisPort = 6379;
        String lockKey = "my_lock";
        String uniqueIdentifier = "unique_id";
        int lockTimeout = 10; // 锁的过期时间
 
        try (Jedis jedis = new Jedis(redisHost, redisPort)) {
            RedisDistributedLock distributedLock = new RedisDistributedLock(jedis, lockKey, uniqueIdentifier, lockTimeout);
 
            if (distributedLock.acquireLock()) {
                try {
                    // 成功获取到锁,执行业务逻辑
                    System.out.println("Do something here...");
                } finally {
                    // 释放锁
                    distributedLock.releaseLock();
                }
            } else {
                // 获取锁失败
                System.out.println("Failed to acquire the lock");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

这种 expire 机制的使用会引入一个新的问题——过期时间不精准. 因为此处设置的过期时间只能是一个经验值(通常情况下偏于保守),既然是经验值,那就做不到百分之百的严谨性. 试想假如占有锁的使用方在业务处理流程中因为一些异常的耗时(如 IO、GC等),导致业务逻辑处理时间超过了预设的过期时间,就会导致锁被提前释放. 此时在原使用方的视角中,锁仍然持有在自己手中,但在实际情况下,锁数据已经被删除,其他取锁方可能取锁成功,于是就可能引起一把锁同时被多个使用方占用的问题,锁的基本性质——独占性遭到破坏.

为解决这个问题,redisson提出新的方案-看门狗策略

看门狗机制

etcd 续约机制与 watchDog 看门狗机制非常类似.

租约,顾名思义,是一份具有时效性的协议,一旦达到租约上规定的截止时间,租约就会失去效力

在使用 etcd 的租约能力时,用户会先预设一个租约过期时间,但并非一个绝对意义的截止时间,因为租约是支持动态续约操作的. 接下来用户可以异步启动一个续约协程,按照指定的时间节奏进行续约操作,延长租约的过期时间. 这样实现的好处在于:

使用方规避了因为业务逻辑处理过长,导致租约数据(包含了分布式锁)提前过期释放的问题(因为有续约协程持续进行续约)
规避了因锁持有方宕机导致租约数据无法释放,内部包含的分布式锁产生死锁问题(倘若持有方宕机了,那续约协程也就停止工作了,续约工作未正常执行,租约会在下一个过期时间节点被回收,包含的锁数据也就释放了)

在这里插入图片描述

import redis.clients.jedis.Jedis;
 
public class RedisDistributedLockWithWatchdog {
    // 其他代码...
 
    private volatile boolean running = true;
 
    public void stopWatchdog() {
        running = false;
    }
 
    public boolean acquireLockWithWatchdog() {
        // 获取锁的代码...
 
        if ("OK".equals(result)) {
            // 获取锁成功,开启看门狗定时刷新任务
            Thread watchdogThread = new Thread(() -> {
                try {
                    while (running) {
                        Thread.sleep(WATCHDOG_INTERVAL * 1000L); // 等待一段时间后刷新锁
                        jedis.expire(lockKey, lockTimeout); // 刷新锁的过期时间
                    }
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                }
            });
            watchdogThread.setDaemon(true);
            watchdogThread.start();
            return true;
        }
        return false;
    }
 
    public static void main(String[] args) {
        // 其他代码...
 
        try (Jedis jedis = new Jedis(redisHost, redisPort)) {
            RedisDistributedLockWithWatchdog distributedLock = new RedisDistributedLockWithWatchdog(jedis, lockKey, uniqueIdentifier, LOCK_TIMEOUT);
 
            if (distributedLock.acquireLockWithWatchdog()) {
                try {
                    // 执行业务逻辑...
 
                    // 成功获取到锁,业务处理结束后释放锁并停止看门狗
                    distributedLock.releaseLock();
                    distributedLock.stopWatchdog();
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                } finally {
                    // 释放锁
                    distributedLock.releaseLock();
                }
            } else {
                // 获取锁失败
                System.out.println("Failed to acquire the lock");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/488308.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

9.2024

使用冒泡排序给{10 ,1,35,61,89,36,55}排序 代码&#xff1a; public class 第九题 {public static void main(String[] args) {int a[]{10,1,35,61,89,36,55};for (int i0;i<a.length-1;i){for (int j0;j<a.length-1;j){if (a[j]>a[j1]){int temp0;tempa[j];a[j]a[…

数字量化值Digital Number, 辐射亮度Radiance, 反射率Reflectance,发射率Emissive

我们经常听到有人困惑于图像的像素值储存的是什么信息&#xff0c;以及如何获取所需的值。这里我们总结以下几个概念。 数字量化值&#xff08;Digital Number &#xff1a;DN&#xff09; 像素值的通用术语是数字量化值或DN值&#xff0c;它通常被用来描述还没有校准到具有意…

hbase启动错误-local host is“master:XXXX“ destination is:master

博主的安装前提&#xff1a; zookeeper安装完成&#xff0c;且启动成功 hdfs高可用安装&#xff0c;yarn高可用安装&#xff0c;且启动成功 报错原因&#xff1a;端口配置不对 解决方案&#xff1a; 输入&#xff1a;hdfs getconf -confKey fs.default.name 然后把相应的…

Spring Cloud 网关Gateway + 配置中心

网关 网络的接口&#xff0c;负责请求的路由、转发、身份校验 路由&#xff1a;告诉请求去哪找 转发&#xff1a;请求找不到直接带请求过去 路由及转发 判断前端请求的规则就这么配 当前情况下只需要访问8080端口 就可以完成对全部微服务的访问 路由属性 登录校验 没必要在每…

如果有意外,这个窗口就会弹出,希望你们能够看到!——夜读(逆天打工人爬取热门微信文章解读)

第一个日二更 引言Python 代码第一篇 定时任务运行结果 第二篇 人民日报 【夜读】最好的教养&#xff0c;是对家人和颜悦色结尾 时间不会无缘无故增加 也不会无缘无故减少 我们唯一能够控制就是 加大时间的密度 引言 为了不让我在大庭广众下大喊我是沙比 我来更新文章啦 这次带…

网络七层模型之物理层:理解网络通信的架构(一)

&#x1f90d; 前端开发工程师、技术日更博主、已过CET6 &#x1f368; 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1 &#x1f560; 牛客高级专题作者、打造专栏《前端面试必备》 、《2024面试高频手撕题》 &#x1f35a; 蓝桥云课签约作者、上架课程《Vue.js 和 E…

【漏洞复现】商混ERP系统 DictionaryEdit.aspx接口处存在SQL注入漏洞

免责声明&#xff1a;文章来源互联网收集整理&#xff0c;请勿利用文章内的相关技术从事非法测试&#xff0c;由于传播、利用此文所提供的信息或者工具而造成的任何直接或者间接的后果及损失&#xff0c;均由使用者本人负责&#xff0c;所产生的一切不良后果与文章作者无关。该…

并发编程之的虚假唤醒和精准唤醒的详细解析

虚假唤醒 例子 wait&#xff08;&#xff09;是object类自带的方法&#xff0c;在jdk有介绍&#xff0c;有可能出现中断、虚假唤醒 也就是在下面的例子中 if(number ! 0){this.wait(); } 当线程成功进入if语句块中&#xff0c;发生了中断&#xff0c;cpu跑去调度别的进程了&am…

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇

厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件开发之功能结构篇 好几年前&#xff0c;应朋友之邀&#xff0c;为其工厂的厨余垃圾处理设备研发一套用于对现场的生产及维护进行远程查看、管理和质量监控的厨余垃圾处理设备工业监控PLC连接APP小程序智能软硬件系统。 因为…

MVC框架里的几种对象

Java语言是一门面向对象的编程语言&#xff0c;所有都用类表达&#xff0c;入口都是一个类&#xff0c;没有独立的main&#xff08;&#xff09;函数&#xff0c;类的实例化就是对象。 简单来讲类包括数据和方法&#xff0c;方法就是操作&#xff0c;是实现业务逻辑的地方&…

获取高德安全码SHA1

高德开发者平台上给的三种方法 获取安全码SHA1&#xff0c;这里我自己使用的是第三种方法。 1、通过Eclipse编译器获取SHA1 使用 adt 22 以上版本&#xff0c;可以在 eclipse 中直接查看。 Windows&#xff1a;依次在 eclipse 中打开 Window -> Preferances -> Androi…

C++动态内存管理:new/delete与malloc/free的对比

在C中&#xff0c;动态内存管理是一个至关重要的概念。它允许我们在程序运行时根据需要动态地分配和释放内存&#xff0c;为对象创建和销毁提供了灵活性。在C中&#xff0c;我们通常会用到两对工具&#xff1a;new/delete 和 malloc/free。虽然它们都能够完成类似的任务&#x…

「10」文本(GDI+):添加文字,可设置背景添加移动效果

「10」文本&#xff08;GDI&#xff09;添加文字&#xff0c;可设置背景添加移动效果 在OBS软件里&#xff0c;通过来源组件「文本&#xff08;GDI&#xff09;」&#xff0c;您可以添加任意您想要呈现的文字&#xff0c;在直播窗口中显示&#xff0c;它可以是提示语、广告词、…

【双指针】Leetcode 盛最多水的容器

题目解析 11. 盛水最多的容器 木桶效应&#xff0c;寻找一个区间使得这个区间的体积最大 算法讲解 1. 暴力枚举 遍历这个容器&#xff0c;将每一个区间的体积求出来&#xff0c;然后找出最大的 class Solution { public:int maxArea(vector<int>& height){int n…

【技术总结】常用指标mAP, mIoU, mDice, mFscore, aAcc 实现

mAP mAP 全称是 mean Average Precision. 其中 mean 这个操作是在 class 级别上, 因此只需要将所有类别平均即可. 所有需要关注的就是 AP. AP 是 Precision-Recall 曲线和坐标轴围成的面积. 提到曲线可能会感觉比较懵 – 模型的预测对或者不对都是确定的, 哪里来的曲线呢? 想…

字节算法岗二面,凉凉。。。

节前&#xff0c;我们星球组织了一场算法岗技术&面试讨论会&#xff0c;邀请了一些互联网大厂朋友、参加社招和校招面试的同学&#xff0c;针对算法岗技术趋势、大模型落地项目经验分享、新手如何入门算法岗、该如何准备、面试常考点分享等热门话题进行了深入的讨论。 汇总…

php反序列化刷题1

[SWPUCTF 2021 新生赛]ez_unserialize 查看源代码想到robots协议 看这个代码比较简单 直接让adminadmin passwdctf就行了 poc <?php class wllm {public $admin;public $passwd; }$p new wllm(); $p->admin "admin"; $p->passwd "ctf"; ec…

【第三方登录】Google邮箱

登录谷歌邮箱开发者 https://console.developers.google.com/ 先创建项目 我们用的web应用 设置回调 核心主要&#xff1a; 1.创建应用 2.创建客户端ID 3.设置域名和重定向URL 4.对外公开&#xff0c;这样所有的gmail邮箱 都能参与测试PHP代码实现 引入第三方包 h…

【云能耗管理系统在某大型商场的应用】安科瑞Acrel-EIOT能源物联网平台方案

摘要&#xff1a;依据对上海市某大型商场现场考察的结果&#xff0c;提出通过建设云能耗管理系统的方案来改善商场能耗的管理现状。首先充分搜集建筑信息和设备运行工况&#xff0c;合理设计系统实施方案&#xff0c;解决现场数据采集和传输障碍&#xff0c;完成云能耗管理系统…

常用设计模式介绍

前言 简说设计模式。 文章目录 前言一、设计模式的要素1、设计模式解决的问题2、设计模式分类1&#xff09;创建型设计模式2&#xff09;结构型设计模式3&#xff09;行为型设计模式 二、详细介绍1、创建型设计模式1&#xff09;工厂方法模式2&#xff09;抽象工厂模式3&#x…