当前位置: 首页 > news >正文

谈谈Redis缓存和数据库一致性

目录

1、缓存问题

2、更新缓存

3、删除缓存

4、最终方案

5、缓存分类

5.1、缓存穿透

5.2、缓存击穿

5.2、缓存雪崩

6、示例


前言

        Redis 作为缓存与数据库之间的通信模式能够显著提升系统性能,减少数据库的压力。

        通过合理使用 Redis 进行数据存取,并结合适当的缓存失效与更新策略,可以确保数据一致性和系统的高效性。

如下图所示:


1、缓存问题

        引入缓存提高性能,在提高性能的同时,也会引入数据不一致性和并发问题,通常引入更多组件也会加大业务系统的复杂度。

1、简单业务场景

在简单业务数据量不大的场景,无论是读请求还是写请求,直接操作数据库即可。

如下图所示:

2、项目引入缓存

        随着项目请求量越来越大,这时如果每次都从数据库中读数据,会有性能问题。

这个阶段通常的做法是,引入「缓存」来提高读性能。

如下图所示:

3、数据同步

在引入redis作为缓存之后,就会出现redis数据和数据库数据如何同步的现象。

相对于简单的方案:全量导入缓存

  • 数据库的数据,全量刷入缓存(不设置失效时间)

  • 写请求只更新数据库,不更新缓存

  • 启动一个定时任务,定时把数据库的数据,更新到缓存中

优点:

所有读请求都可以直接「命中」缓存,不需要再查数据库,性能非常高。

缺点:

        缓存利用率可能不高(部分redis-key),受定时任务影响导致数据会出现不一致(时间有关)。

4、缓存利用率

        想要缓存利用率「最大化」,可以容易想到的方案是,缓存中只保留最近访问的「热数据」。如下图所示:

设置缓存的失效时间。

处理方案:

  • 写请求依旧只写数据库

  • 读请求先读缓存,如果缓存不存在,则从数据库读取,并重建缓存

  • 同时,写入缓存中的数据,都设置失效时间

        随着时间的推移,不常用的key都会逐渐「过期」淘汰掉,最终缓存中保留的,都是经常被访问的「热数据」,缓存利用率得以最大化。


2、更新缓存

1、数据一致性

        基于上面介绍的定时任务虽然也可以做到数据同步,但是局限性比较大,为了实现缓存利用率最大化。

        因此,需要在更新数据库后,即使更新缓存,否则缓存和数据库还是会有时间差,导致查询redis缓存的值是旧值,存在利用率不高的现象。

期望:

        当数据发生更新时,我们不仅要操作数据库,还要一并操作缓存。

当数据库和缓存都更新,又存在先后问题,那对应的方案就有 2 个:

  1. 先更新缓存,后更新数据库

  2. 先更新数据库,后更新缓存

此时也有可能存在先后操作的时候,出现失败的场景。

1) 先更新缓存,后更新数据库

        如果缓存更新成功了,但数据库更新失败,那么此时缓存中是最新值,但数据库中是「旧值」。

        虽然此时读请求可以命中缓存,拿到正确的值,但是,一旦缓存「失效」,就会从数据库中读取到「旧值」,重建缓存也是这个旧值。

        这时用户会发现自己之前修改的数据又「变回去」了,对业务造成影响。

2) 先更新数据库,后更新缓存

        如果数据库更新成功了,但缓存更新失败,那么此时数据库中是最新值,缓存中是「旧值」。之后的读请求读到的都是旧数据,只有当缓存「失效」后,才能从数据库中得到正确的值。

        这时用户会发现,自己刚刚修改了数据,但却看不到变更,一段时间过后,数据才变更过来,对业务也会有影响。

可见,无论谁先谁后,但凡后者发生异常,就会对业务造成影响。

2、并发场景

并发引发的一致性问题

        假设我们采用「先更新数据库,再更新缓存」的方案,并且两步都可以「成功执行」的前提下,如果存在并发。

有线程 A 和线程 B 两个线程,需要更新「同一条」数据,会发生这样的场景:

  1. 线程 A 更新数据库(X = 1)

  2. 线程 B 更新数据库(X = 2)

  3. 线程 B 更新缓存(X = 2)

  4. 线程 A 更新缓存(X = 1)

最终 X 的值在缓存中是 1,在数据库中是 2,发生不一致。

        从分析可知,尽管A 虽然先于 B 发生,但 B 操作数据库和缓存的时间,却要比 A 的时间短,执行时序发生「错乱」,最终这条数据结果是不符合预期的。

而另外先更新缓存、再更新数据库也会出现相似的场景。

总结:

        因为每次数据发生变更,都「无脑」更新缓存,但是缓存中的数据不一定会被「马上读取」,这就会导致缓存中可能存放了很多不常访问的数据,浪费缓存资源。


3、删除缓存

对于删除缓存,也有对应的方案 2 种:

  1. 先删除缓存,后更新数据库

  2. 先更新数据库,后删除缓存

首先先分析一下,当删除缓存、数据库任意一部出现失败的情况,都会导致读取不一致。

如下图所示:

当两者都成功的话,也会出现并发问题。如下图所示:

如果是先删缓存、再更新数据库,在没有出现失败时可能会导致数据的不一致。

        如果在实际的应用中,出于某些考虑我们需要选择这种方式,那有办法解决这个问题吗?答案是有的,那就是采用延时双删的策略,延时双删的基本思路如下:

  • 删除缓存;
  • 更新数据库;
  • sleep N毫秒;
  • 再次删除缓存。
public void write(String key, Object data) {Redis.delKey(key);db.updateData(data);Thread.sleep(1000);Redis.delKey(key);
}

        而先更新数据库,后删除缓存这⼀种情况也会出现问题,比如更新数据库成功了,但是在删除缓存的阶段出错了没有删除成功,那么此时再读取缓存的时候每次都是错误的数据了。

此时可以:

引入重试机制。

如果无限制的重试,会增加性能开销,同时需要合理设置重试次数。

基于上面的考虑,采用异步重试--MQ组件。

  • 消息队列保证可靠性:写到队列中的消息,成功消费之前不会丢失(重启项目也不担心)

  • 消息队列保证消息成功投递:下游从队列拉取消息,成功消费后才会删除消息,否则还会继续投递消息给消费者(符合我们重试的场景)

此时解决方案就是利用消息队列进行删除的补偿。

4、最终方案

对于为什么引入mq的本质,防止删除缓存失败的时候,数据库重启,导致操作任务丢失。

由于基于先更新数据库,后删除缓存。

        有⼀个缺点就是会对业务代码造成大量的侵入,因此对 Mysql 数据库更新操作后再从 binlog 日志中找到相应的操作。

可以订阅 Mysql 数据库的 binlog 日志对缓存进行操作。

如下图所示:

具体的业务逻辑⽤语⾔描述如下:

  • 请求 线程A 先对数据库进行更新操作;
  • 在对 Redis 进行删除操作的时候发现报错,删除失败;
  • 此时将Redis 的 key 作为消息体发送到消息队列中;
  • 系统接收到消息队列发送的消息后再次对 Redis 进行删除操作;

        当然在读写分离 + 主从复制延迟的情况下,可以结合延迟双删的策略,最大程度的减少缓存不一致问题。

以下对延迟双删的策略进行介绍:

1.工作原理

  1. 第一次删除缓存

    • 在更新数据库之前,应用程序首先从 Redis 中删除相关缓存。这可以确保未来的读取请求不会查询到过期或错误的数据。
  2. 更新数据库

    • 然后,程序对数据库进行写操作,更新数据。
  3. 引入短暂延迟

    • 在成功更新数据库后,引入一个短暂的延迟(例如 50 毫秒),这段时间允许主从复制机制完成对数据的同步,对数据变化有所“缓冲”。
  4. 第二次删除缓存

    • 在延迟后,再次删除 Redis 中的缓存。此时,即使在从数据库中读取数据的请求仍然存在,经过这段延迟,主从复制完成后,确保主数据库的数据更新已经卷入从库。

2. 解决主从复制问题的机制

数据一致性

  • 防止旧数据读取:通过第一次删除缓存和随后引入的延迟,可以有效防止在数据库更新后短时间内的旧数据读取。如果数据在从数据库上的复制尚未完成,这段时间的延迟将确保后续查询能够处理正确的请求。

  • 确保完整更新:第二次删除缓存是一个冗余的步骤,用于确保即使在并发操作下,过期的数据不会被保留在缓存中。

系统的健壮性

  • 异步处理:由于这种策略允许数据库在处理完更新后再进行第二次删除操作,系统可以更灵活地应对并发请求,并维护更高的一致性。

总结

        延迟双删策略通过结合数据库更新、缓存删除和引入短暂延迟,可以有效解决缓存与主从复制之间的一致性问题。

        通过确保在删除缓存之前,数据库的写操作已经完成,并赋予时间对主从数据库进行同步,从而避免读取到过时的数据。


总结:

1、想要提高应用的性能,可以引入「缓存」来解决。

2、引入缓存后,需要考虑缓存和数据库一致性问题,可选的方案有:「更新数据库 + 更新缓存」、「更新数据库 + 删除缓存」。

3、更新数据库 + 更新缓存方案,在「并发」场景下无法保证缓存和数据一致性,且存在「缓存资源浪费」和「机器性能浪费」的情况发生。

4、在更新数据库 + 删除缓存的方案中,「先删除缓存,再更新数据库」在「并发」场景下依旧有数据不一致问题,解决方案是「延迟双删」,但这个延迟时间很难评估,所以推荐用「先更新数据库,再删除缓存」的方案。

5、在「先更新数据库,再删除缓存」方案下,为了保证两步都成功执行,需配合「消息队列」或「订阅变更日志」的方案来做,本质是通过「重试」的方式保证数据一致性。

6、在「先更新数据库,再删除缓存」方案下,「读写分离 + 主从库延迟」也会导致缓存和数据库不一致,缓解此问题的方案是「延迟双删」,凭借经验发送「延迟消息」到队列中,延迟删除缓存,同时也要控制主从库延迟,尽可能降低不一致发生的概率。


5、缓存分类

在使用缓存机制过程中,也会出现一些比较特殊的场景。

如下图所示:

5.1、缓存穿透

1.定义

        缓存穿透是指查询一个不存在的数据。例如,当用户请求一个不存在的 ID(如查询一个未注册的用户)时,系统会直接查询数据库,因为缓存中没有相关数据。

        由于这些请求始终发往数据库,可能导致数据库压力过大。

2.特征

  • 主要关注的是请求的数据在缓存中完全不存在。
  • 每个请求都必然直接查询数据库,无法利用缓存。

3.解决方案

  • 校验请求参数(如非法请求参数直接返回错误)。
  • 引入防刷机制(如验证码)来限制请求频率。
  • 布隆过滤器:在请求到来时,首先检查布隆过滤器。布隆过滤器可以快速判断某项数据是否可能存在,避免无效请求直接到达数据库。
  • 缓存空值:在得到空的查询结果时,可以将这个空值结果存储到 Redis 中,并设定一个过期时间。之后再访问同样的用户 ID 时,可以直接返回空值,而不再访问数据库。

如下图所示:

原理:

布隆过滤器的基本原理如下:

  1. 位数组:布隆过滤器使用一个位数组(bit array)来表示集合,位数组的每个位置可以存储为0或1。

  2. 哈希函数:布隆过滤器使用多个不同的哈希函数将元素映射到位数组中的几个位置。每个哈希函数都会根据输入元素计算出一个索引值。

  3. 添加元素:要添加元素时,通过每个哈希函数计算出多个索引,然后将位数组中这些索引对应的位置设为1。

  4. 查询元素:要查询元素时,同样使用哈希函数计算出对应的索引。如果所有这些索引在位数组中都是1,则可以认为这个元素可能在集合中;如果有任何一个索引是0,则可以确定这个元素不在集合中。

特性

  • 可能产生误判:布隆过滤器可能会返回“存在”的错误结果(即假阳性),但如果返回“不存在”则准确。
  • 不可删除:一旦加入元素,无法将其删除,这也是设计上的 trade-off。

代码示例:

import java.util.BitSet;
import java.util.Random;public class BloomFilter {private BitSet bitSet;  // 位数组private int size;       // 位数组的大小private int hashCount;  // 哈希函数的数量public BloomFilter(int size, int hashCount) {this.size = size;this.hashCount = hashCount;this.bitSet = new BitSet(size);  // 初始化位数组}// 添加元素public void add(String item) {// 针对每个哈希函数位置哈希值并设置位数组for (int i = 0; i < hashCount; i++) {int hash = hash(item, i);bitSet.set(hash);  // 设置该位置为1}}// 查询元素public boolean mightContain(String item) {// 检查通过所有哈希函数计算的位数组位置for (int i = 0; i < hashCount; i++) {int hash = hash(item, i);if (!bitSet.get(hash)) {return false;  // 如果有任意一个位置为0,返回不在集合中}}return true;  // 所有位置为1,返回可能在集合中}// 哈希函数private int hash(String item, int seed) {// 使用简单的算法计算哈希值,实际上可以使用更复杂的哈希函数return (item.hashCode() + seed) % size;}public static void main(String[] args) {BloomFilter bloomFilter = new BloomFilter(100, 5);// 添加元素bloomFilter.add("apple");bloomFilter.add("banana");// 检查元素System.out.println(bloomFilter.mightContain("apple"));  // 输出: trueSystem.out.println(bloomFilter.mightContain("banana")); // 输出: trueSystem.out.println(bloomFilter.mightContain("orange")); // 输出: false(可能在集合中) }
}

5.2、缓存击穿

1.定义

        缓存击穿是指某个热点数据的缓存失效(或过期),在失效的瞬间,同时有大量请求涌入,导致数据库的压力急剧增加。

        这种情况通常发生在用户频繁请求某些数据,并在这些数据的缓存失效时。

2.特征

  • 通常是针对某些热门数据的请求。
  • 多个并发请求在数据刚过期的瞬间直接访问数据库。

3.解决方案

  • 加锁机制

            对缓存中失效的数据的请求进行分布式锁控制。只有第一个请求会去数据库加载数据,其余请求则等待。当数据加载完成后,所有请求都能从缓存中读取数据。
  • 设置更长的缓存有效期

            针对热点数据,适当延长其缓存时间,减少过期次数,从而降低击穿的概率。
  • 预热缓存

           在应用程序的低峰期,主动将热门数据预先加载到缓存中,确保在高峰期不会因缓存失效导致击穿。

5.2、缓存雪崩

1.定义

        缓存雪崩是在特定时刻,多个缓存数据同时失效,导致大量请求同时涌向数据库,造成数据库压力骤增。

        这种情况通常发生在缓存系统的集中失效,比如一段时间内大批缓存设置了相同的过期时间。

2.特征

  • 涉及到多个缓存数据的失效,而不仅仅是单一数据。
  • 在短时间内,都发起请求的情况。

3.解决方案

  • 为缓存设置不同的过期时间,避免集中失效的现象。
  • 采用随机过期时间策略,使缓存的失效时间分散。
  • 监控缓存健康状况,及时发现并处理异常。


6、示例

        下面是一个结合 延迟双删 策略的代码示例,该策略用于确保在更新数据库后,缓存中的数据保持一致。这个示例使用 Java 和 Redis 的操作示例,

        假设使用 Spring Data Redis 来进行数据库操作。

示例场景

        假设有一个用户数据更新的场景,涉及到更新用户信息并且需要确保 Redis 缓存中的用户信息是最新的。

代码示例

以下是一个简单的 Java 方法,其中实现了先更新数据再删除缓存,并结合延迟双删策略:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;@Service
public class UserService {@Autowiredprivate UserRepository userRepository; // 假设有一个 JPA 仓库来处理 User 数据库操作@Autowiredprivate RedisTemplate<String, User> redisTemplate; // Redis 模板// 更新用户信息@Transactional // 确保数据库操作是原子性的public void updateUser(Long userId, User updatedUser) {// 1. 删除缓存(第一次删除)String cacheKey = "user:" + userId;redisTemplate.delete(cacheKey);// 2. 更新数据库userRepository.save(updatedUser); // 假设 save 是一个更新操作// 3. 延迟try {Thread.sleep(50); // 短暂延迟,给主从同步提供时间} catch (InterruptedException e) {Thread.currentThread().interrupt();}// 4. 再次删除缓存(第二次删除)redisTemplate.delete(cacheKey);}// 获取用户信息public User getUser(Long userId) {String cacheKey = "user:" + userId;// 尝试从缓存中获取User user = redisTemplate.opsForValue().get(cacheKey);if (user != null) {return user;}// 如果缓存未命中,则从数据库加载user = userRepository.findById(userId).orElse(null);// 同时,将从数据库中获得的用户信息放入缓存if (user != null) {redisTemplate.opsForValue().set(cacheKey, user);}return user;}
}

代码解析

  1. 删除缓存(第一次删除):

    • 在更新数据库之前,应用从 Redis 缓存中删除与用户 ID 相关的缓存。这有助于确保后续的读取请求不会读取到过时的数据。
  2. 更新数据库

    • 通过 JPA 仓库更新用户信息。
  3. 延迟

    • 使用 Thread.sleep(50) 引入短暂延迟,以允许主从数据库之间的数据同步。这里的延迟时间可以根据系统性能和网络延迟进行调整。
  4. 再次删除缓存(第二次删除):

    • 再次删除缓存项,以确保若有并发操作(其他请求可能在延迟期间发生)存在,也能保持一致性。
  5. 获取用户信息

    • 在获取用户信息时,首先尝试从缓存中获取,未命中则从数据库加载并更新缓存。

        延迟双删策略结合 Redis 缓存和数据库更新,提供了一种有效的方式来管理数据一致性,确保系统在处理高并发情况下能够可靠地保持缓存的数据准确性。


参考文章:

1、缓存和数据库一致性问题,看这篇就够了-CSDN博客

2、【Redis】如何保证Redis缓存与数据库的一致性?_redis缓存如何与数据库保持一致-CSDN博客

相关文章:

谈谈Redis缓存和数据库一致性

目录 1、缓存问题 2、更新缓存 3、删除缓存 4、最终方案 5、缓存分类 5.1、缓存穿透 5.2、缓存击穿 5.2、缓存雪崩 6、示例 前言 Redis 作为缓存与数据库之间的通信模式能够显著提升系统性能&#xff0c;减少数据库的压力。 通过合理使用 Redis 进行数据存取&#xff…...

JWT深度解析:现代Web身份验证的通行证-优雅草卓伊凡

# JWT深度解析&#xff1a;现代Web身份验证的通行证 ## 一、JWT的本质与构成 ### 1.1 JWT的定义解析 JWT&#xff08;JSON Web Token&#xff09;是一种**开放标准&#xff08;RFC 7519&#xff09;**&#xff0c;用于在各方之间安全地传输信息作为JSON对象。这种信息可以被…...

VTK|.obj文件数据处理+Jet/Viridis/CoolToWarm/Grayscale/Rainbow/风格颜色渲染

文章目录 处理OBJ文件Jet渲染风格Viridis渲染风格CoolToWarm渲染风格Grayscale渲染风格Rainbow渲染风格切换风格按钮槽函数&#xff08;可优化&#xff09;相关代码github链接 将 .obj 数据进行 Elevation 着色并可视化渲染的完整流程 和.ply文件处理方式一样 处理OBJ文件 vo…...

如何通过服务主体获取 Azure 凭据

本文详细讲解如何通过 Azure 服务主体生成凭据,使应用程序能够安全访问 Azure 资源(如部署 Container Apps)。以下步骤基于 Azure Portal 操作,适用于自动化部署、CI/CD 等场景。 步骤 1:登录 Azure Portal 访问 Azure 门户。使用 Azure 账户(需具备订阅管理员权限)登录…...

Kubernetes探针生产环境实战指南

一、探针的本质&#xff1a;应用健康的智能体检系统 想象你的应用是一个高空走钢丝的演员&#xff0c;Kubernetes探针就像三位安全员&#xff1a; 启动探针&#xff1a;检查演员是否站稳&#xff08;应用是否完成初始化&#xff09;就绪探针&#xff1a;确认演员准备好表演&a…...

node.js 实战——express图片保存到本地或服务器(七牛云、腾讯云、阿里云)

本地 ✅ 使用formidable 读取表单内容 npm i formidable ✅ 使用mime-types 获取图片后缀 npm install mime-types✅ js 中提交form表单 document.getElementById(uploadForm).addEventListener(submit, function(e){e.preventDefault();const blob preview._blob;if(!blob)…...

线代第二章矩阵第五、六、七节矩阵的转置、方阵的行列式、方阵的伴随矩阵

文章目录 矩阵的转置转置性质对称矩阵与反对称矩阵 方阵的行列式方阵的伴随矩阵&#xff08;重要&#xff09; 矩阵的转置 转置性质 &#xff08;1&#xff09; &#xff08;2&#xff09; &#xff08;3&#xff09; &#xff08;4&#xff09;注意这个&#xff1a; 扩展&a…...

经验:从CAN到以太网为主的车载网络架构升级

引言 新能源汽车智能化与网联化的进程中&#xff0c;传统CAN总线已难以满足高带宽、低延迟的通信需求&#xff0c;车载以太网逐步成为新一代电子架构的核心骨干。本文基于工程实践&#xff0c;系统性解析车载以太网的核心技术、协议栈、拓扑设计及工具链升级策略&#xff0c;助…...

基于FPGA婴儿安全监护系统(蓝牙小程序监测)

基于FPGA婴儿安全监护系统 前言一、芯片手册阅读二、代码分析1.温湿度驱动2.转速等级设置模块3.电机转速控制模块 总结视频演示 前言 实时监测车内温湿度数据&#xff08;DTH11温湿度模块&#xff09;----实时控制风扇驱动速度&#xff08;结合温湿度进行控制&#xff09;----…...

嵌入式 C 语言控制语句

目录 1. 控制语句 2. 分支语句 2.1 if else 2.2 switch 3. 循环语句 3.1 goto 3.2 while 循环 3.3 do while 循环 3.4 for 循环 3.5 例题 3.6 循环控制语句 3.6.1 break 3.6.2 continue 1. 控制语句 控制语句分为&#xff1a;顺序语句&#xff0c;分支语句&#xff0…...

leaflet-velocity风场粒子效果及数据处理

一&#xff0c;后台给到的数据 {"msg": "success","code": 200,"data": {"startLat": 39.3,"endlat": 41.2,"latdel": 0.099999994,"startLon": 115.3,"endLon": 117.50001,"…...

React 实现 JWT 登录验证的最小可运行示例

下面是一个用 React 实现 JWT 登录验证的最小可运行示例&#xff0c;包含&#xff1a; React 前端&#xff1a;登录、保存 Token、获取用户数据。模拟后端&#xff1a;用 mock API&#xff08;你也可以接真后端&#xff09;。 &#x1f9f1; 技术栈 React&#xff08;使用 Vi…...

MySQL报错解决过程

我在调试datagrip的时候&#xff0c;显示拒绝连接&#xff0c;开始的时候&#xff0c;我以为只是服务没有开启&#xff0c;结果到后来在网上搜索各种解决办法无果后&#xff0c;就选择卸载&#xff0c;卸载之后安装新的MySQL 以下就是我的解决过程。 如果只是在使用外置软件&…...

更多 QVariant 使用案例

以下是 QVariant 的其他典型应用场景及代码示例&#xff0c;涵盖更多实际开发需求&#xff1a; 6. 数据库查询结果处理 处理数据库字段的异构数据类型&#xff08;如整数、字符串、日期等&#xff09;&#xff1a; QSqlQuery query; query.exec("SELECT name, age, crea…...

WPF中解决数据绑定不匹配的问题

在 WPF 开发中&#xff0c;IValueConverter 和 IMultiValueConverter 接口是非常实用的工具&#xff0c;它们允许你在数据绑定过程中对数据进行转换。 IValueConverter 接口示例 IValueConverter 接口用于单值转换&#xff0c;它包含 Convert 和 ConvertBack 两个方法。Conve…...

学习Cesium Entities

🌐 Cesium中的Entities系统趣味学习 📊 Entities系统架构流程图 #mermaid-svg-Lkue5O3gYOkEVSbD {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-Lkue5O3gYOkEVSbD .error-icon{fill:#552222;}#mermaid-svg-Lku…...

Spark处理过程-案例数据清洗

&#xff08;一&#xff09;需求说明 准备十条符合包含用户信息的文本文件&#xff0c;每行格式为 姓名,年龄,性别&#xff0c;需要清洗掉年龄为空或者非数字的行。 例如&#xff1a; 张三,25,男 李四,,女 王五,30,男 赵六,a,女 孙七,35,男 周八,40,女 吴九,abc,男 郑十,45,女…...

【AI提示词】马斯洛需求分析专家

提示说明 专业的心理学需求分析专家&#xff0c;熟悉马斯洛需求层次理论及其在不同文化背景下的适用性。 提示词 # Role: 马斯洛需求分析专家## Profile - language: 中文 - description: 专业的心理学需求分析专家&#xff0c;熟悉马斯洛需求层次理论及其在不同文化背景下的…...

【WebRTC-13】是在哪,什么时候,创建编解码器?

Android-RTC系列软重启&#xff0c;改变以往细读源代码的方式 改为 带上实际问题分析代码。增加实用性&#xff0c;方便形成肌肉记忆。同时不分种类、不分难易程度&#xff0c;在线征集问题切入点。 问题&#xff1a;编解码器的关键实体类是什么&#xff1f;在哪里&什么时候…...

Kuikly 安装环境篇

1、安装版本号为2024.1.1 的Android studio&#xff08;如使用高版本的Android studio需要更改JDK版本号为17&#xff09; 2、JDK版本使用17&#xff08;如需要修改JDK&#xff1a;Android Studio -> Settings -> Build,Execution,Deployment -> Build Tools -> Gr…...

npm create vite@latest my-vue-app 解读

背景发荧光的样式。 filter属性的学习&#xff1a;filter - CSS&#xff1a;层叠样式表 | MDN 复习一下em 组件的调用: 是msg让“ViteVue”显示出来的&#xff01;&#xff01; a标签的targte属性&#xff1a; 组件之间怎么传值的&#xff1a; &#xff0c;没看懂code标签怎么…...

【本地搭建npm私服】使用Verdaccio

使用Verdaccio搭建本地NPM私服及私有包管理指南 一、Verdaccio安装与基础配置 1. 安装Verdaccio # 全局安装Verdaccio npm install -g verdaccio# 检查版本 verdaccio --version2. 启动服务 verdaccio启动后默认监听4873端口&#xff0c;访问 http://localhost:4873 3. 配…...

Chroma:一个开源的8.9B文生图模型

Chroma 模型讲解 一、模型概述 Chroma 是一个基于 FLUX.1-schnell 的 8.9B 参数模型。它采用了 Apache 2.0 许可证&#xff0c;完全开源&#xff0c;允许任何人使用、修改和在其基础上进行开发&#xff0c;不存在企业限制。该模型目前正在训练中&#xff0c;训练数据集从 20M…...

量子通信技术及其在信息安全中的应用:开启无条件安全通信的新时代

前言 在数字化时代&#xff0c;信息安全是全球关注的焦点。随着传统加密技术面临量子计算等新兴技术的挑战&#xff0c;量子通信作为一种基于量子力学原理的新型通信技术&#xff0c;因其无条件安全的特性而备受关注。量子通信不仅能够有效抵御量子计算的威胁&#xff0c;还能为…...

【杂谈】Godot 2D游戏窗口设置

如切如磋&#xff0c;如琢如磨。 目录 一、引言二、设置&#xff08;一&#xff09;基本尺寸&#xff08;二&#xff09;拉伸&#xff08;三&#xff09;手持设备朝向&#xff08;四&#xff09;​​窗口模式​​ 一、引言 在开发2D游戏时&#xff0c;​​窗口尺寸的设定是游戏…...

MySQL 8.0 OCP认证考试题库持续更新

MySQL是属于甲骨文Oracle公司的一个世界知名的免费数据库产品&#xff0c;使用的范围广、企业多、人员也多&#xff0c;所以对MySQL认证关注的人也不少&#xff0c;MySQL的证书与Oracle的证书使用的是同一个模板&#xff0c;只是在内部的介绍上稍有不同&#xff0c;MySQL认证考…...

C++GO语言微服务基础技术②

目录 01 protobuf语法回顾 02 protobuf的编译、和其他序列化比较 03 查看protoc编译文件对比自定义封装 04 grpc安装简介 05 grpc服务远程调用作业布置 06 作业-grpc-server端 07 作业-grpc-client端 01 protobuf语法回顾 ## 编译 protobuf> 回顾&#xff1a;C 编译 …...

【使用switch结构输出季节】2021-11-23

缘由用switch语句设计程序一年有12个月-编程语言-CSDN问答 void 使用switch结构输出季节(int y) {//缘由https://ask.csdn.net/questions/7577096?spm1005.2025.3001.5141std::cout << y << "\t";switch (y){case 3: case 4: case 5:std::cout <<…...

【Bootstrap V4系列】学习入门教程之 组件-下拉菜单(Dropdowns)

Bootstrap V4系列 学习入门教程之 组件-下拉菜单&#xff08;Dropdowns&#xff09; 下拉菜单&#xff08;Dropdowns&#xff09;一、Overview 概述二、Accessibility 可访问性三、Examples3.1 Single button 单按钮3.2 Split button 分割按钮 四、Sizing 尺寸 下拉菜单&#x…...

基础编程题目集 6-8 简单阶乘计算

本题要求实现一个计算非负整数阶乘的简单函数。 函数接口定义&#xff1a; int Factorial( const int N ); 其中N是用户传入的参数&#xff0c;其值不超过12。如果N是非负整数&#xff0c;则该函数必须返回N的阶乘&#xff0c;否则返回0。 裁判测试程序样例&#xff1a; #in…...

解决word里插入公式后打不开的问题

小铃铛最近在写毕业论文了&#xff0c;需要在文档里插入公式&#xff0c;然鹅一插入就卡死了&#xff0c;直接关闭文档后就再也打不开了&#xff0c;报错什么确定磁盘有空间&#xff08;&#xff1f;总之就是文档损坏的意思&#xff09; 这个时候不要慌&#xff0c;先把word后缀…...

android studio开发:设置屏幕朝向为竖屏,强制应用的包体始终以竖屏(纵向)展示

在 Android 中&#xff0c;要强制应用的包体始终以竖屏&#xff08;纵向&#xff09;展示&#xff0c;可以通过以下几种方式来实现&#xff1a; ✅ 方式一&#xff1a; 在 AndroidManifest.xml 中设置 Activity 的方向&#xff0c;这是最常用的方法。对所有需要强制竖屏的 Ac…...

中国自动驾驶研发解决方案,第一!

4月28日&#xff0c;IDC《中国汽车云市场(2024下半年)跟踪》报告发布&#xff0c;2024下半年中国汽车云市场整体规模达到65.1亿元人民币&#xff0c;同比增长27.4%。IDC认为&#xff0c;自动驾驶技术深化与生成式AI的发展将为汽车云打开新的成长天花板&#xff0c;推动云计算在…...

OpenCv实战笔记(3)基于opencv实现调用摄像头并实时显示画面

一、实现效果 二、实现原理 使用 OpenCV 打开摄像头&#xff0c;持续捕获视频帧&#xff0c;并在一个窗口中实时显示这些帧&#xff0c;直到用户按下 ESC 键退出。整体流程&#xff1a;打开摄像头&#xff08;cv::VideoCapture&#xff09;>创建图像显示窗口&#xff08;cv…...

SpringBoot3 + Druid + DynamicDataSource + PgSQL 连接池优化方案

问题描述 使用 SpringBoot Druid DynamicDataSource PgSQL 时遇到的连接过多未释放问题&#xff0c;一方面是升级DB Core对DB做Tuning&#xff0c;另一方面是优化Druid数据库连接池方案。 关键优化方向 连接泄漏检测与回收 连接有效性验证 合理的连接池大小配置 闲置连接…...

C++ 深入解析 数据结构中的 AVL树的插入 涉及的旋转规则

欢迎来到干货小仓库 "普通程序员Google 超级程序员" 1、AVL 树的概念 二叉搜索树虽可以缩短查找的效率&#xff0c;但如果数据有序或接近有序二叉搜索树将退化为单支树&#xff0c;查找元素相当于在顺序表中搜索元素&#xff0c;效率低下。 例如在这种情况下&…...

c++中的引用

1&#xff0c;引用的基本使用&#xff1a; 作用&#xff1a;给变量起别名 语法&#xff1a;数据类型 &别名 原名 #include<iostream> using namespace std; int main() {int a10;int &ba;cout<<"a "<<a<<endl;cout<<&quo…...

零拷贝的简单复习

PageCache PageCache是内核缓冲区 DMA 没有DMA前的IO&#xff1a;整个数据的传输过程&#xff0c;都需要 CPU 亲自参与搬运数据的过程&#xff0c;而且这个过程中CPU 是不能做其他事情的 CPU发起IO 磁盘将数据放到磁盘缓冲区 CPU将磁盘缓冲区数据放到内核缓冲区 CPU将内核缓…...

CCF编程能力等级认证 一级 第一次课

介绍 CCF 编程能力等级认证&#xff08;GESP&#xff09;为青少年计算机和编程学习者提供学业能力验证的规则和平台&#xff0c;由中国计算机学会发起并主办。 每年考试分四次&#xff0c;时间是每年的3月、6月、9月、12月&#xff0c;以当年每期公布的时间为准。 GESP适用年…...

芯片测试之Open-Short Test全解析:从原理到实战

大家好&#xff0c;我是硅言。最近在开发NORD的AC、DC测试程序&#xff0c;准备和大家聊聊NOR Flash一套完整的AC、DC测试&#xff0c;要测哪些参数&#xff0c;如何测试等等。​​OS测试&#xff08;Open-Short Test&#xff0c;开短路测试&#xff09;​​作为芯片测试"…...

文件包含 任意文件读取

文件处理漏洞--文件包含 - wizard骑士 - 博客园 1&#xff0c;什么是文件包含 程序开发人员一般会吧重复使用的函数写道单个文件中&#xff0c;需要使用某个函数时直接调用此文件&#xff0c;无需再次编写&#xff0c;文件调用的过程就是文件包含&#xff0c;所以将包含的文件…...

string[字符串中第一个的唯一字符][蓝桥杯]

使用哈希表解决 class Solution { public:int firstUniqChar(string s) {int arr[26];for(int i0;i<s.size();i){arr[s[i]-a];}for(int i0;i<s.size();i){if(arr[s[i]-a]1)return i;}return -1;} };...

sql server限制用户只能访问特定表

一个老系统的sqlserver 数据库需要新建一个用户&#xff0c;并限制这个新用户只能访问指定的几个数据表。 1.夺权 创建用户简单&#xff0c;但是登录用户没有管理权&#xff0c;windows管理员登录用户也没有管理权限&#xff0c;这就需要夺权&#xff0c;在单用户模式下&…...

中级网络工程师知识点2

1.netstat -r:显示路由表信息 netstat -a:显示所有活动的TCP连接数以及计算机正在监听的TCP和UDP端口 netstat -e:显示以太网统计信息 netstat -n:以数字形式显示网络地址和端口号 2.display multicast forwarding-table 命令的作用是查看组播转发表信息。 display multic…...

SQL常用操作大全:复制表、跨库查询、删除重复数据

大家好&#xff0c;欢迎来到程序视点&#xff01;我是你们的老朋友.小二&#xff01; SQL常用操作精华总结 表结构与数据操作 复制表结构&#xff1a; SELECT * INTO b FROM a WHERE 1<>1 (SQL Server专用) SELECT TOP 0 * INTO b FROM a (更通用) 拷贝表数据&#…...

辰鳗科技朱越洋:紧扣时代契机,全力投身能源转型战略赛道

国家能源局于4月28日出台的《关于促进能源领域民营经济发展若干举措的通知》&#xff08;以下简称《通知》&#xff09;&#xff0c;是继2月民营企业座谈会后深化能源领域市场化改革的关键政策&#xff0c;标志着民营经济在“双碳”目标引领下正式进入能源转型的核心赛道。 自…...

java 破解aspose.words 18.6 使用

资源包&#xff1a;https://download.csdn.net/download/qq_36598111/90787167 jar包是破解过的&#xff0c;直接可以使用。 引入jar&#xff0c;要引入本地的&#xff0c;不要直接引入仓库的 <dependency><groupId>com.aspose</groupId><artifactId>…...

基于鸢尾花(Iris)数据集的分类模型

本文适合初学者入门&#xff0c;涵盖了数据加载、预处理、建模、训练和评估的全过程。 &#x1f3af; 项目目标 使用机器学习算法&#xff08;如K近邻KNN&#xff09;对鸢尾花的品种进行分类。 &#x1f9f0; 所需工具 Python 3.x 安装的库&#xff1a; pip install scikit…...

电容知识小结

1.同样是电容&#xff0c;1uf的陶瓷电容和1uf的铝电解电容是不一样的&#xff1b; 2.实际的电容等效为ESR C ESL;ESR等效电阻和ESL等效电感&#xff1b; 3.铝电解电容&#xff0c;瓷片电容和钽电容。 4.电容是容纳和释放电荷的电子器件&#xff1b; 5.电容的工作&#xff1a;…...

基于springboot+vue的校园部门资料管理系统

开发语言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7数据库工具&#xff1a;Navicat12开发软件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;Maven3.3.9 系统展示 系统登录 学生组…...