【Redis】Redis面试题详解与使用案例(金三银四面试专栏启动)

news2024/12/28 18:54:17

📫作者简介:小明java问道之路,2022博客之星全国TOP3,专注于后端、中间件、计算机底层、架构设计演进与稳定性建工设优化。

文章内容兼具广度深度、大厂技术方案,对待技术喜欢推理加验证,就职于知名金融公司后端高级工程师。

        

📫 热衷分享,喜欢原创~ 关注我会给你带来一些不一样的认知和成长。

        

🏆 2022博客之星全国TOP3 | CSDN博客专家 | 后端领域优质创作者 | CSDN内容合伙人

🏆 InfoQ(极客邦)签约作者、阿里云专家 | 签约博主、51CTO专家 | TOP红人、华为云享专家

        

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~ 


🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

专栏系列(点击解锁)

学习路线(点击解锁)

知识定位

🔥Redis从入门到精通与实战🔥

Redis从入门到精通与实战

围绕原理源码讲解Redis面试知识点与实战

🔥MySQL从入门到精通🔥

MySQL从入门到精通

全面讲解MySQL知识与企业级MySQL实战

🔥计算机底层原理🔥

深入理解计算机系统CSAPP

以深入理解计算机系统为基石,构件计算机体系和计算机思维

Linux内核源码解析

围绕Linux内核讲解计算机底层原理与并发

🔥数据结构与企业题库精讲🔥

数据结构与企业题库精讲

结合工作经验深入浅出,适合各层次,笔试面试算法题精讲

🔥互联网架构分析与实战🔥

企业系统架构分析实践与落地

行业最前沿视角,专注于技术架构升级路线、架构实践

互联网企业防资损实践

互联网金融公司的防资损方法论、代码与实践

🔥Java全栈白宝书🔥

精通Java8与函数式编程

本专栏以实战为基础,逐步深入Java8以及未来的编程模式

深入理解JVM

详细介绍内存区域、字节码、方法底层,类加载和GC等知识

深入理解高并发编程

深入Liunx内核、汇编、C++全方位理解并发编程

Spring源码分析

Spring核心七IOC/AOP等源码分析

MyBatis源码分析

MyBatis核心源码分析

Java核心技术

只讲Java核心技术

 

本文目录

本文目录

本文导读

一、Redis接入指南

1、Redis接入集群模式(推荐)

2、Redis接入哨兵模式(仅做了解,不推荐)

二、Redis使用案例

1、Redis增删改查多种数据结构实现

2、Redis缓存穿透、雪崩、击穿与解决办法

2.1、Redis缓存穿透

2.2、Redis缓存雪崩

2.3、Redis缓存击穿

3、Redis实现限流

3.1、基于Redis的incr

3.2、基于Redis的List、zset等数据结构

4、Redis分布式锁

5、测试环境测试

总结


本文导读

本文提供了两种 Redis 的接入指南,集群模式接入Redis、哨兵模式接入Redis,避免工作中的小伙伴只会背不会用。

Redis使用案例模块主要是为了能够快速开发与使用,给出了一个百万QPS写法的Redis增删改查多种数据结构实现,Redis缓存穿透、雪崩、击穿与解决办法,Redis实现简单的限流策略以及Redis分布式锁, Redis 测试和管理工具Redis Desktop Manager 

文章兼具广度深度,让许多读者对大厂技术方案有进一步了解,在底层原理方面配合推荐的的博客,使用效果更佳!

一、Redis接入指南

Redis 接入分为哨兵模式和集群模式。

哨兵模式,基于哨兵集群实现主从切换,可以看作是简单主从模式的扩展(哨兵模式主要用于Redis主从同步架构,主节点宕机需要哨兵节点监控、通知,选举);

集群模式下需要注意的在哨兵模式下,多个服务器在Redis中存储相同的数据,这是浪费。集群模式可以看作是Redis的分布式存储。

1、Redis接入集群模式(推荐)

JedisRedisson、spring-data-redis三者的比较

Jedis 是 Redis 官方推荐的面向 Java 的操作Redis 的客户端,通过jedis我们可以实现连接Redis,以及操作 Redis 。,如果想在 Java 环境下操作 Redis ,需要安装相应的 Redis 驱动程序,也就 jedis.jar 包,然后将该驱动添加至 Java 的 classpath 中。

spring-data-redis是spring-data模块的一部分,RedisTemplate方式是SpringBoot集成Redis的客户端方式 ,专门用来支持在spring管理项目对redis的操作,使用java操作redis最常用的是使用jedis,但并不是只有jedis可以使用,spring-data-redis提供了redis的java客户端的抽象(org.springframework.data.redis.core.RedisTemplate)并且本身就属于spring的一部分,比起单纯的使用Jedis,更加稳定,管理起来更加自动化.。

Redisson 是一个在Redis的基础上实现的Java驻内存数据网格。它不仅提供了一系列的分布式的Java常用对象,还提供了许多分布式服务。支持的主要功能:分布式锁、分布式服务、数据序列化、分布式对象处理

<dependency>

   <groupId>org.springframework.data</groupId>

   <artifactId>spring-data-redis</artifactId>

   <version>${redis.version}</version>

</dependency>

<dependency>

   <groupId>redis.clients</groupId>

   <artifactId>jedis</artifactId>

   <version>${redis.client.version}</version>

</dependency>

<dependency>

   <groupId>org.redisson</groupId>

   <artifactId>redisson</artifactId>

   <version>${redisson.version}</version>

</dependency>

通用Spring配置:${}中的“”字符串为配置

!-- JedisPool连接池 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.maxActive}"/>
    <property name="maxIdle" value="${redis.maxIdle}"/>
    <property name="minIdle" value="${redis.minIdle}"/>
    <property name="maxWaitMillis" value="${redis.maxWait}"/>
    <property name="testWhileIdle" value="${redis.testWhileIdle}"/>
    <property name="timeBetweenEvictionRunsMillis" value="${redis.timeBetweenEvictionRunsMillis}"/>
    <property name="minEvictableIdleTimeMillis" value="${redis.minEvictableIdleTimeMillis}"/>
</bean>

<!-- Redis配置类 -->
<bean id="redisClusterConfiguration" class="com.pinganfu.mallstock.dal.redis.MyRedisClusterConfiguration">
    <property name="nodeAddress" value="${redis.cluster.nodeAddress}"/>
    <property name="maxRedirects" value="${redis.cluster.max-redirects}"/>
</bean>

<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/>
    <constructor-arg name="poolConfig" ref="poolConfig"/>
    <property name="password" value="${redis.pass}"/>
    <property name="timeout" value="${redis.timeout}"/>
    <property name="usePool" value="true"/>
</bean>
<!--SpringRedis序列化配置 -->
<bean id="stringRedisSerializer"
      class="org.springframework.data.redis.serializer.StringRedisSerializer"/>

<!-- Redis执行器 -->
<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="keySerializer" ref="stringRedisSerializer"/>
    <property name="hashKeySerializer" ref="stringRedisSerializer"/>
</bean>

<!-- Redis缓存操作类 -->
<bean id="cacheExecutor" class="com.pinganfu.mallstock.dal.redis.RedisExecutorImpl">
    <property name="redisTemplate" ref="redisTemplate"/>
    <property name="systemPrefix" value="${redis.systemPrefix}"/>
</bean>​​​​​​​

2、Redis接入哨兵模式(仅做了解,不推荐)

<bean id="configBean" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    <property name="location"> <value>redis.properties</value> </property>
</bean>

<!-- 哨兵配置 -->
<bean id="sentinelConfig" class="org.springframework.data.redis.connection.RedisSentinelConfiguration">
    <constructor-arg name="master" value="${redis.masterName}"/>
    <constructor-arg name="sentinelHostAndPorts">
        <set>
            <value>${redis.hostAndPort1}</value>
            <value>${redis.hostAndPort2}</value>
            <value>${redis.hostAndPort3}</value>
        </set>
    </constructor-arg>
</bean>

<!-- JedisPool连接池 -->
<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <!-- 最大分配的对象数 -->
    <property name="maxTotal" value="${redis.pool.maxActive}"/>
    <!-- 最大能够保持idel状态的对象数 -->
    <property name="maxIdle" value="${redis.pool.maxIdle}"/>
    <!-- 当池内没有返回对象时,最大等待时间 -->
    <property name="maxWaitMillis" value="${redis.pool.maxWait}"/>
    <!-- 测试池化连接有效性 -->
    <property name="testWhileIdle" value="${redis.pool.testWhileIdle}"/>
    <property name="testOnBorrow" value="${redis.pool.testOnBorrow}"/>
    <property name="minIdle" value="${redis.pool.minIdle}"/>
    <property name="testOnReturn" value="${redis.pool.testOnReturn}"/>
    <property name="minEvictableIdleTimeMillis" value="${redis.pool.minEvictableIdleTimeMillis}"/>
    <property name="timeBetweenEvictionRunsMillis" value="${redis.pool.timeBetweenEvictionRunsMillis}"/>
    <property name="softMinEvictableIdleTimeMillis" value="${redis.pool.softMinEvictableIdleTimeMillis}"/>
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="usePool" value="true"/>
    <property name="password" value="${redis.pass}"/>
    <property name="timeout" value="${redis.timeout}"/>
    <property name="poolConfig" ref="jedisPoolConfig"/>
    <constructor-arg index="0" ref="sentinelConfig"/>
</bean>

<!--SpringRedis序列化配置 -->
<bean id="stringRedisSerializer" class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
<bean id="jsonRedisSerializer" class="org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer"/>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory"/>
    <property name="keySerializer" ref="stringRedisSerializer"/>
    <property name="valueSerializer" ref="jsonRedisSerializer"/>
</bean>
<bean id="cacheExecutor" class="com.wanlitong.mcmmessage.util.cache.RedisExecutorImpl">
    <property name="redisTemplate" ref="redisTemplate"/>
    <property name="systemPrefix" value="${redis.systemPrefix}"/>
</bean>

二、Redis使用案例

1、Redis增删改查多种数据结构实现

以下类是使用RedisTemplate构件一个完整的Redis缓存操作类。

实现了很多操作 Redis 的功能,包括不同数据结构的增删改查、限流、异步添加、对存储在指定key的数值加num操作等等

推荐文章:Redis安装步骤和特性以及支持的10种数据类型、Redis跳表与实现源码解析、Redis事务工作原理解析与分布式事务实战、Redis过期删除策略和内存淘汰策略剖析、Redis布隆过滤器工作原理与实战

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Redis缓存操作类封装
 */
@Component
public class RedisExecutorImpl implements CacheExecutor {
    private static final Log logger = LogFactory.getLog(RedisExecutorImpl.class);
    
    @Value("${redis.systemPrefix}")
    private String systemPrefix;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private RedisTemplate<String, Object> redisTemplate4Num;

    @Override
    public void set(String key, int timeout, Object value) {
        String redisKey = systemPrefix + key;
        logger.info("RedisExecutorImpl set redisKey=" + redisKey + ",value=" + value + ",timeout=" + timeout);
        redisTemplate.opsForValue().set(redisKey, value, timeout, TimeUnit.SECONDS);
    }

    @Override
    public Object getData(String key) {
        logger.info("RedisExecutorImpl getData key=" + key);
        return redisTemplate.opsForValue().get(key);
    }

    @Override
    public void setData(String key, long timeout, Object value) {
        logger.info("RedisExecutorImpl setData key=" + key + ",value=" + value + ",timeout=" + timeout);
        redisTemplate.opsForValue().set(key, value, timeout, TimeUnit.MILLISECONDS);
    }

    @Override
    public Object get(String key) {
        logger.info("RedisExecutorImpl get key=" + key);
        return redisTemplate.opsForValue().get(systemPrefix + key);
    }

    @Override
    public Object get4Num(String key) {
        logger.info("RedisExecutorImpl get key=" + key);
        return redisTemplate4Num.opsForValue().get(systemPrefix + key);
    }

    @Override
    public Object hGet(String key, Object field) {
        return redisTemplate.opsForHash().get(systemPrefix + key, field);
    }

    @Override
    @Async(value = "redisExecutor")
    public void hSet(String key, String hKey, Object value, Long timeout) {
        redisTemplate.opsForHash().put(systemPrefix + key, hKey, value);
        redisTemplate.expire(systemPrefix + key, timeout, TimeUnit.SECONDS);
    }

    /**
     * hDel方法
     *
     * @param hKey
     * @param key
     */
    @Override
    public void hDel(String key, String hKey) {
        redisTemplate.opsForHash().delete(systemPrefix + key, hKey);
    }

    @SuppressWarnings("static-access")
    @Override
    public boolean delete(String key) {
        try {
            redisTemplate.delete(systemPrefix + key);
            return true;
        } catch (Exception e) {
            logger.error("redis delete failed, key =" + systemPrefix + key + ", e=", e);
            return false;
        }
    }

    @Override
    public List<Object> mget(List<String> keyList) {
        List<String> finalKeys = keyList.stream().filter(Objects::nonNull).distinct().map(e -> systemPrefix + e).collect(Collectors.toList());
        return redisTemplate.opsForValue().multiGet(finalKeys);
    }

    @Override
    @Async(value = "redisExecutor")
    public void mset(Map<String, Object> map) {
        redisTemplate.opsForValue().multiSet(map);
    }

  /*  @Override
    @Async
    public void mset4Num(Map<String, Object> map) {
        redisTemplate4Num.opsForValue().multiSet(map);
    }*/

    @SuppressWarnings("static-access")
    @Override
    public boolean keyExistsIgnoreException(String key) {
        try {
            return redisTemplate.hasKey(systemPrefix + key);
        } catch (Exception e) {
            logger.error("redis keyExistsIgnoreException failed, key =" + systemPrefix + key + ", e=", e);
            return false;
        }
    }

    @SuppressWarnings("static-access")
    @Override
    public boolean deleteCacheKey(String key) {
        try {
            redisTemplate.delete(key);
            return true;
        } catch (Exception e) {
            logger.error("redis deleteCacheKey failed, key =" + key + ", e=", e);
            return false;
        }
    }

    @Override
    @Async(value = "redisExecutor")
    public void asyncSet(String key, int timeout, Object value) {
        redisTemplate.opsForValue().set(systemPrefix + key, value, timeout, TimeUnit.SECONDS);
    }

    @Override
    public boolean expireKey(String key, long timeout) {
        logger.info("RedisExecutorImpl expireKey key=" + key + " timeout=" + timeout);
        boolean result = false;
        result = redisTemplate.expire(key, timeout, TimeUnit.MILLISECONDS);
        return result;
    }

    /**
     * 对存储在指定key的数值执加delta操作
     *
     * @param key   key
     * @param delta num
     * @return num
     */
    @Override
    public Long incr(String key, long delta) {
        logger.info("RedisExecutorImpl expireKey key=" + key + " delta=" + delta);
        Long increment = redisTemplate4Num.opsForValue().increment(systemPrefix + key, delta);
        logger.info("current value" + increment);
        return increment;
    }


    /**
     * 对存储在指定key的数值执加1操作
     *
     * @param key key
     * @return num
     */
    @Override
    public Long incr(String key) {
        return incr(key, 1L);
    }

    /**
     * 获取key过期时间
     *
     * @param key
     * @param timeUnit
     * @return
     */
    @Override
    public Long getExpireTime(String key, TimeUnit timeUnit) {
        return redisTemplate.getExpire(systemPrefix + key, timeUnit);
    }

    /**
     * 设置缓存 永久有效
     *
     * @param key   不带系统前缀
     * @param value
     */
    @Override
    public void set(String key, Object value) {
        logger.info("RedisExecutorImpl set redisKey=" + key + ",value=" + value);
        redisTemplate.opsForValue().set(key, value);
    }
}

2、Redis缓存穿透、雪崩、击穿与解决办法

推荐文章:【Redis】Redis缓存穿透、缓存雪崩、缓存击穿详解与解决办法(Redis专栏启动) 

2.1、Redis缓存穿透

缓存穿透是指缓存和数据库中都没有的数据,而用户不断发起请求,特别大不存在的数据。这时的用户很可能是攻击者,攻击会导致数据库压力过大。

缓存穿透通常发生在以下两种情况下:缓存中的数据和数据库中的数据被错误删除,导致缓存和数据库中没有数据;黑客恶意攻击并故意访问大量读取不存在数据的企业;

解决方案:

1、非法请求的限制:在接收参数时过滤业务接口中的非法值、空值、负值和空值

2、布隆过滤器:一种类似于哈希表的算法。它使用所有可能的查询条件来生成位图,该位图将用于在数据库查询之前进行过滤。如果没有,它将被直接过滤,以减轻数据库级别的压力;

3、缓存空值:一个相对简单的解决方案。在第一次查询不存在的数据后,密钥和相应的空值也被放入缓存,但设置为较短的过期时间

2.2、Redis缓存雪崩

缓存服务挂掉或者热点缓存失效,所有请求都去查数据库,导致数据库连接不够或者数据库处理不过来,从而导致整个系统不可用。

缓存雪崩两个原因:

1、大量(热点)数据同时过期,导致本应请求缓存的数据,需要从数据库中检索;

解决方案:1、随机、微调甚至设置来设置过期时间;2、添加一个互斥锁,构建缓存后,释放锁,返回空值或默认值;3、双 key 策略,主key是原始缓存, 备key是副本缓存。当主key失败时,可以访问备份key;4、后台更新缓存策略,用定时任务或者消息队列更新或删除Redis缓存。

2、Redis故障宕机(服务挂掉),无法处理请求,再次请求数据库。

解决方案:1、服务熔断或请求限流机制;2、使用主从节点来构建集群

2.3、Redis缓存击穿

缓存击穿是指缓存中没有数据,但数据库中有数据(通常缓存时间到期)。此时,由于并发用户太多,读取缓存并不能读取数据,同时又去数据库检索数据,数据库压力瞬间增加,导致压力过大。击穿和雪崩的区别在于,击穿是针对特定的热点数据,而雪崩是所有数据。

解决方案:

1、缓存设置不过期,并且后台异步更新缓存

2、添加一个互斥锁,构建缓存后,释放锁,返回空值或默认值

3、Redis实现限流

推荐文章: Redis分布式限流与Redis实现限流的四种方式(Redis专栏启动)

在生产中的限流包括网关层的限流与Redis实现的限流策略,主要有基于Redisincrement方法作为vaule实现次数的递增,然后设置缓存过期时间来实现固定时间窗口、Listzset实现的滑动窗口,以及RedisLua脚本实现分布式限流。

3.1、基于Redis的incr

@SuppressWarnings("rawtypes")
private RedisTemplate redisTemplate;

// key自增
Long count = redisTemplate.opsForValue().increment(key, 1);

// 设置时间窗口
boolean expire = redisTemplate.expire(key, cacheTimeSecond, TimeUnit.SECONDS);

3.2、基于Redis的List、zset等数据结构

// 获取令牌,返回 null 代表当前令牌桶中无令牌,则拒绝请求
Object result = redisTemplate.opsForList().leftPop("limit_list");

// 在令牌桶中添加令牌(令牌需要唯一)
redisTemplate.opsForList().rightPush("limit_list",UUID.randomUUID().toString());

4、Redis分布式锁

推荐文章:Redis实现分布式锁解析与应用(Redis专栏启动) 

Redis分布式锁被广泛使用。本质上,分布式锁的目标是在Redis中占据一把“钥匙”。当其他进程想要占用一个密钥时,它们必须放弃,或者在发现已经存在密钥时重试。

@SuppressWarnings("rawtypes")
private RedisTemplate redisTemplate;

// 加锁
boolean isGetLock = redisTemplate.opsForValue().setIfAbsent(key, value, timeout, TimeUnit.MILLISECONDS);

// 锁是自己的,才释放
if (isGetLock) 
    redisTemplate.delete(key);

5、测试环境测试

Redis缓存数据库工具:Redis Desktop Manager

Redis Desktop Manager 类似于 Navicat 的 Redis缓存数据库管理工具,点击进入后和 Navicat 一样首先是连接数据库服务器,输入名字/地址/端口号等等。

连接成功后就可以看到服务器中的数据库,在Redis中我们的数据都是存在一个键里面,就可以操作,鼠标停留在小图标上即可显示功能,使用起来很简单,建议对照官网操作一遍。

总结

本文提供了两种 Redis 的接入指南,集群模式接入Redis、哨兵模式接入Redis,避免工作中的小伙伴只会背不会用。

Redis使用案例模块主要是为了能够快速开发与使用,给出了一个百万QPS写法的Redis增删改查多种数据结构实现,Redis缓存穿透、雪崩、击穿与解决办法,Redis实现简单的限流策略以及Redis分布式锁, Redis 测试和管理工具Redis Desktop Manager 

文章兼具广度深度,让许多读者对大厂技术方案有进一步了解,在底层原理方面配合推荐的的博客,使用效果更佳!

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~ 

🍅 文末获取联系 🍅  👇🏻 精彩专栏推荐订阅收藏 👇🏻

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ipv6实验

r1的配置为 [r1]int g0/0/0 [r1-GigabitEthernet0/0/0]ip address 12.1.1.1 24 [r1]int lo0 [r1-LoopBack0]ip address 1.1.1.1 32 [r1]ip route-static 0.0.0.0 0 12.1.1.2 r2的配置为 [r2]int g0/0/0 [r2-GigabitEthernet0/0/0]ip address 12.1.1.2 24 [r2]int lo0 […

小红书破局品牌增长:4大阶段+8个种草建议

品牌如何从激烈的竞争中突围&#xff0c;成为快速增长的“黑马”&#xff1f;本文就和大家一起聊聊围绕产品面对不同阶段的人群“种草”策略&#xff0c;希望能够帮助品牌更好地与用户沟通并提升营销效率&#xff0c;实现品效合一。 1、种草1.0 —— 立住产品&#xff0c;抢占赛…

Minecraft 1.19.2 Fabric模组开发 10.建筑生成

我们本次尝试在Fabric 1.19.2中生成一个自定义的建筑。 效果展示效果展示效果展示 由于版本更新缘故&#xff0c;1.19的建筑生成将不涉及任何Java包的代码编写&#xff0c;只需要在数据包中对建筑生成进行自定义。 1.首先我们要使用游戏中的结构方块制作一个建筑,结构方块使用…

企业内部沟通即时通讯软件要怎么选?

随着企业信息化的快速发展&#xff0c;为了工作效率的提高&#xff0c;即时通讯工具已经成为了众多企业办公时的标配&#xff0c;同时&#xff0c;各大企业对即时通讯功能的要求也越来越高。但是&#xff0c;现在市场上即时通信软件众多&#xff0c;各种功能和服务都是参差不齐…

python爬虫基本库的使用

博主简介&#xff1a;博主是一个大二学生&#xff0c;主攻人工智能领域研究。感谢缘分让我们在CSDN相遇&#xff0c;博主致力于在这里分享关于人工智能&#xff0c;C&#xff0c;python&#xff0c;爬虫等方面的知识分享。如果有需要的小伙伴&#xff0c;可以关注博主&#xff…

Java面试基础篇

目录 一、集合 1.集合与集合之间的区别 2.集合子类之间的区别&#xff08;数据结构&#xff09; 二、线程 三、面向对象 继承 多态 四、异常 五、IO流 六、序列化与反序列化 今天给大家分享 Java基础篇的面试题&#xff0c;小编给大家稍微整理了一下&#xff0c;希望即…

RHCE(web服务器)

文章目录一、www简介&#xff08;一&#xff09;网址及HTTP简介&#xff08;二&#xff09;HTTP协议请求的工作流程二、www服务器的类型&#xff08;一&#xff09;仅提供用户浏览的单向静态网页&#xff08;二&#xff09;提供用户互动接口的动态网站三、www服务器的基本配置四…

苹果证书p12和描述文件的创建教程

在hbuilderx或apicloud这些uniapp框架工具打包苹果APP的时候&#xff0c;需要p12证书和证书profile文件来编译&#xff0c;目前网上很少使用windows电脑生成p12证书的教程&#xff0c;官方的教程都是需要使用苹果电脑来创建的。 这里&#xff0c;我们这篇文章来教会大家如何使…

【虚拟仿真】Unity3D中实现鼠标悬浮UI上显示文字

推荐阅读 CSDN主页GitHub开源地址Unity3D插件分享简书地址我的个人博客 大家好&#xff0c;我是佛系工程师☆恬静的小魔龙☆&#xff0c;不定时更新Unity开发技巧&#xff0c;觉得有用记得一键三连哦。 一、前言 本篇文章实现一个鼠标悬浮在UI上显示文字的功能&#xff0c;实…

LMK04828时钟芯片配置历程——SPI接口

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 LMK04828时钟芯片配置历程——SPI接口总结最近有一个开发板需要去调试&#xff0c;开发板上包含了AD9371和LMK04828时钟芯片&#xff0c;而我的任务是需要将他们都配置起来。…

c++入门之输入输出命名空间

文章目录前言一、输入输出二、命名空间1.使用命名空间的原因2.命名空间定义3.命名空间的定义注意事项&#xff08;1&#xff09;命名空间只能在全局范围使用&#xff08;2&#xff09;命名空间可以嵌套&#xff08;3&#xff09;命名空间是开放的,可以随时添加新的成员&#xf…

mysql流程控制

前言&#xff1a; &#x1f44f;作者简介&#xff1a;我是笑霸final&#xff0c;一名热爱技术的在校学生。 &#x1f4dd;个人主页&#xff1a;个人主页1 || 笑霸final的主页2 &#x1f4d5;系列专栏&#xff1a;数据库 &#x1f4e7;如果文章知识点有错误的地方&#xff0c;请…

QT---制作简易串口助手

一、ui制作打开QTCreator创建一个新文件2.进入UI设计界面进行设计进入ui界面后&#xff0c;选择相应的控件将串口助手的样子给做出来&#xff0c;我选择的是如下的控件做这个串口助手&#xff1a;1.按钮&#xff1a;2.下拉列表3.标签4.组合框5.文本编辑绘制ui界面如下&#xff…

如何用Windows自带命令修改文件和图片的MD5

首先说下&#xff0c;md5到底是啥&#xff0c;它是一段固定长度的数据。无论原始数据是多长或多短&#xff0c;其MD5值都是128bit。另外md5是确定性&#xff0c;一个原始数据的MD5值是唯一的&#xff0c;同一个原始数据不可能会计算出多个不同的MD5值&#xff1b;类似人类的身份…

快速搭建前后端分离项目

后端 配置文件和依赖 创建一个SpringBoot项目&#xff0c;采用Mybatis-Plus快速构建项目。 application.yml进行配置 server:port: 80spring:datasource:username: rootpassword: 123456url: jdbc:mysql://localhost:3306/ems?useSSLfalse&useUnicodetrue&charact…

C++——哈希

目录 unordered系列关联式容器 unordered_mapunordered_map在线文档说明 unordered_map的接口说明 unordered系列优势 哈希 解决哈希冲突 1.闭散列——开放定址法 思考&#xff1a;哈希表什么情况下进行扩容&#xff1f;如何扩容&#xff1f; 插入元素代码 查找元素 …

Linux操作系统--用户和群组(保姆级教程)

用户和群组 用户 什么是用户&#xff0c;即登录到linux操作系统的账号就是用户。在linux操作系统中账户的类别主要有三类&#xff1a;1、超级管理员&#xff08;root&#xff09;,在linux中超级管理员的账户是root&#xff0c;这个root账户就类似于windows操作系统中administr…

pom.xml配置中引入Oracle依赖

pom.xml配置中引入Oracle依赖1. Download Driver1.1 pom.xml2.Awakening1. Download Driver 因为Oracle是要收费的&#xff0c;所以不能通过远程的方式来引入&#xff0c;可以通过mvn指令导入到Maven本地仓库。 下载地址 Oracle Website: https://www.oracle.com/database/tech…

MyBatis案例 | 使用映射配置文件实现CRUD操作——查询所有数据

本专栏主要是记录学习完JavaSE后学习JavaWeb部分的一些知识点总结以及遇到的一些问题等&#xff0c;如果刚开始学习Java的小伙伴可以点击下方连接查看专栏 本专栏地址&#xff1a;&#x1f525;JavaWeb Java入门篇&#xff1a; &#x1f525;Java基础学习篇 Java进阶学习篇&…

各类SDR的USB接口一致性测试

最近用高带宽示波器测了好几个SDR产品的USB2接口一致性。由于探头数量只有1个&#xff0c;所以不能测全所有的项目。但已经包含了最主要的USB眼图&#xff08;信号质量&#xff09;项目。 待测件包含&#xff1a; 1.原版RTL-SDR 2.自制RTL-SDR 3.HackRF 4.无线电罗盘v0.8 测试…