flea-cache使用之Redis哨兵模式接入

在这里插入图片描述

Redis哨兵模式接入

  • 1. 参考
  • 2. 依赖
  • 3. 基础接入
    • 3.1 定义Flea缓存接口
    • 3.2 定义抽象Flea缓存类
    • 3.3 定义Redis客户端接口类
    • 3.4 定义Redis客户端命令行
    • 3.5 定义哨兵模式Redis客户端实现类
    • 3.6 定义Redis哨兵连接池
    • 3.7 定义Redis哨兵配置文件
    • 3.8 定义Redis Flea缓存类
    • 3.9 定义抽象Flea缓存管理类
    • 3.10 定义Redis哨兵模式Flea缓存管理类
    • 3.11 定义Redis客户端工厂类
    • 3.12 定义Redis客户端策略上下文
    • 3.13 定义哨兵模式Redis客户端策略
    • 3.14 Redis集群模式接入自测
  • 4. 进阶接入
    • 4.1 定义抽象Spring缓存
    • 4.2 定义Redis Spring缓存类
    • 4.3 定义抽象Spring缓存管理类
    • 4.4 定义Redis哨兵模式Spring缓存管理类
    • 4.5 spring 配置
    • 4.6 缓存自测
  • 结语

1. 参考

flea-cache使用之Redis哨兵模式接入 源代码

2. 依赖

jedis-3.0.1.jar

<!-- Java redis -->
<dependency><groupId>redis.clients</groupId><artifactId>jedis</artifactId><version>3.0.1</version>
</dependency>

spring-context-4.3.18.RELEASE.jar

<!-- Spring相关 -->
<dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>4.3.18.RELEASE</version>
</dependency>

spring-context-support-4.3.18.RELEASE.jar

<dependency><groupId>org.springframework</groupId><artifactId>spring-context-support</artifactId><version>4.3.18.RELEASE</version>
</dependency>

3. 基础接入

3.1 定义Flea缓存接口

IFleaCache 可参考笔者的这篇博文 Memcached接入,不再赘述。

3.2 定义抽象Flea缓存类

AbstractFleaCache 可参考笔者的这篇博文 Memcached接入,不再赘述。

3.3 定义Redis客户端接口类

RedisClient 可参考笔者的这篇博文 Redis集群模式接入,不再赘述。

3.4 定义Redis客户端命令行

RedisClientCommand 可参考笔者的这篇博文 Redis分片模式接入,不再赘述。

3.5 定义哨兵模式Redis客户端实现类

FleaRedisSentinelClient 即Flea哨兵模式Redis客户端实现,封装了Flea框架操作Redis缓存的基本操作。它内部具体操作Redis缓存的功能,由Jedis哨兵连接池获取Jedis实例对象完成,包含读、写、删除Redis缓存的基本操作方法。

哨兵模式下,单个缓存接入场景,可通过如下方式使用:

   RedisClient redisClient = new FleaRedisSentinelClient.Builder().build();// 执行读,写,删除等基本操作redisClient.set("key", "value"); 

哨兵模式下,整合缓存接入场景,可通过如下方式使用:

   RedisClient redisClient = new FleaRedisSentinelClient.Builder(poolName).build();// 执行读,写,删除等基本操作redisClient.set("key", "value");  

当然每次都新建Redis客户端显然不可取,我们可通过Redis客户端工厂获取Redis客户端。
哨兵模式下,单个缓存接入场景,可通过如下方式使用:

   RedisClient redisClient = RedisClientFactory.getInstance(CacheModeEnum.SENTINEL);

哨兵模式下,整合缓存接入场景,可通过如下方式使用:

   RedisClient redisClient = RedisClientFactory.getInstance(poolName, CacheModeEnum.SENTINEL); 
public class FleaRedisSentinelClient extends FleaRedisClient {private JedisSentinelPool jedisSentinelPool;private int maxAttempts;/*** Redis哨兵客户端构造方法 (默认)** @since 2.0.0*/private FleaRedisSentinelClient() {this(CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME);}/*** Redis哨兵客户端构造方法(指定连接池名)** @param poolName 连接池名* @since 2.0.0*/private FleaRedisSentinelClient(String poolName) {super(poolName);init();}/*** 初始化Jedis哨兵实例** @since 2.0.0*/private void init() {if (CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME.equals(getPoolName())) {jedisSentinelPool = RedisSentinelPool.getInstance().getJedisSentinelPool();maxAttempts = RedisSentinelConfig.getConfig().getMaxAttempts();} else {jedisSentinelPool = RedisSentinelPool.getInstance(getPoolName()).getJedisSentinelPool();maxAttempts = CacheConfigUtils.getMaxAttempts();}}@Overridepublic String set(final String key, final Object value) {return new RedisClientCommand<String, JedisSentinelPool, Jedis>(this.jedisSentinelPool, this.maxAttempts) {@Overridepublic String execute(Jedis connection) {if (value instanceof String)return connection.set(key, (String) value);elsereturn connection.set(SafeEncoder.encode(key), ObjectUtils.serialize(value));}}.run();}// 省略。。。。。。/*** 内部建造者类** @author huazie* @version 2.0.0* @since 2.0.0*/public static class Builder {private String poolName; // 连接池名/*** 默认构造器** @since 2.0.0*/public Builder() {}/*** 指定连接池的构造器** @param poolName 连接池名* @since 2.0.0*/public Builder(String poolName) {this.poolName = poolName;}/*** 构建Redis哨兵客户端对象** @return Redis哨兵客户端* @since 2.0.0*/public RedisClient build() {if (StringUtils.isBlank(poolName)) {return new FleaRedisSentinelClient();} else {return new FleaRedisSentinelClient(poolName);}}}
}

该类的构造函数初始化逻辑,可以看出我们使用了 RedisSentinelPool, 下面来介绍一下。

3.6 定义Redis哨兵连接池

我们使用 RedisSentinelPool 来初始化Jedis哨兵连接池实例,其中重点是获取分布式Jedis连接池 ShardedJedisPool ,该类其中一个构造方法如下:

public JedisSentinelPool(String masterName, Set<String> sentinels, final GenericObjectPoolConfig poolConfig, final int connectionTimeout, final int soTimeout, final String password, final int database, final String clientName) {}

Redis哨兵连接池,用于初始化Jedis哨兵连接池实例。

针对单独缓存接入场景,采用默认连接池初始化的方式; 可参考如下:

    // 初始化默认连接池RedisSentinelPool.getInstance().initialize();

针对整合缓存接入场景,采用指定连接池初始化的方式; 可参考如下:

    // 初始化指定连接池RedisSentinelPool.getInstance(group).initialize(cacheServerList);
public class RedisSentinelPool {private static final ConcurrentMap<String, RedisSentinelPool> redisPools = new ConcurrentHashMap<>();private static final Object redisSentinelPoolLock = new Object();private String poolName; // 连接池名private JedisSentinelPool jedisSentinelPool; // Jedis哨兵连接池private RedisSentinelPool(String poolName) {this.poolName = poolName;}/*** 获取Redis哨兵连接池实例 (默认连接池)** @return Redis哨兵连接池实例对象* @since 2.0.0*/public static RedisSentinelPool getInstance() {return getInstance(CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME);}/*** 获取Redis哨兵连接池实例 (指定连接池名)** @param poolName 连接池名* @return Redis哨兵连接池实例对象* @since 2.0.0*/public static RedisSentinelPool getInstance(String poolName) {if (!redisPools.containsKey(poolName)) {synchronized (redisSentinelPoolLock) {if (!redisPools.containsKey(poolName)) {RedisSentinelPool redisSentinelPool = new RedisSentinelPool(poolName);redisPools.put(poolName, redisSentinelPool);}}}return redisPools.get(poolName);}/*** 默认初始化** @since 2.0.0*/public void initialize(int database) {// 省略。。。。。。}/*** 初始化 (非默认连接池)** @param cacheServerList 缓存服务器集* @since 2.0.0*/public void initialize(List<CacheServer> cacheServerList) {// 省略。。。。。。}/*** Jedis哨兵连接池** @return Jedis哨兵连接池* @since 2.0.0*/public JedisSentinelPool getJedisSentinelPool() {if (ObjectUtils.isEmpty(jedisSentinelPool)) {ExceptionUtils.throwFleaException(FleaCacheConfigException.class, "获取Jedis哨兵连接池失败:请先调用initialize初始化");}return jedisSentinelPool;}
}

3.7 定义Redis哨兵配置文件

flea-cache 读取 redis.sentinel.properties(Redis哨兵配置文件),用作初始化 RedisSentinelPool

# Redis哨兵配置
redis.sentinel.switch=1redis.systemName=FleaFrameredis.sentinel.masterName=mymasterredis.sentinel.server=127.0.0.1:36379,127.0.0.1:36380,127.0.0.1:36381#redis.sentinel.password=huazie123redis.sentinel.connectionTimeout=2000redis.sentinel.soTimeout=2000# Redis哨兵客户端连接池配置
redis.pool.maxTotal=100redis.pool.maxIdle=10redis.pool.minIdle=0redis.pool.maxWaitMillis=2000redis.maxAttempts=5redis.nullCacheExpiry=10
  • redis.sentinel.switch : Redis哨兵配置开关(1:开启 0:关闭),如果不配置也默认开启
  • redis.systemName : Redis缓存所属系统名
  • redis.sentinel.masterName : Redis主服务器节点名称
  • redis.sentinel.server : Redis哨兵节点的地址集合
  • redis.sentinel.password : Redis主从服务器节点登录密码(各节点配置同一个)
  • redis.sentinel.connectionTimeout : Redis哨兵客户端socket连接超时时间(单位:ms)
  • redis.sentinel.soTimeout : Redis哨兵客户端socket读写超时时间(单位:ms)
  • redis.pool.maxTotal : Jedis连接池最大连接数
  • redis.pool.maxIdle : Jedis连接池最大空闲连接数
  • redis.pool.minIdle : Jedis连接池最小空闲连接数
  • redis.pool.maxWaitMillis : Jedis连接池获取连接时的最大等待时间(单位:ms)
  • redis.maxAttempts : Redis客户端操作最大尝试次数【包含第一次操作】
  • redis.nullCacheExpiry : 空缓存数据有效期(单位:s)

3.8 定义Redis Flea缓存类

RedisFleaCache 可参考笔者的这篇博文 Redis分片模式接入,不再赘述。

3.9 定义抽象Flea缓存管理类

AbstractFleaCacheManager 可参考笔者的这篇博文 Memcached接入,不再赘述。

3.10 定义Redis哨兵模式Flea缓存管理类

RedisSentinelFleaCacheManager 继承抽象Flea缓存管理类 AbstractFleaCacheManager,用于接入Flea框架管理Redis缓存。

它的默认构造方法,用于初始化哨兵模式下默认连接池的Redis客户端【默认Redis数据库索引为0】, 这里需要先初始化Redis哨兵连接池,默认连接池名为【default】; 然后通过 RedisClientFactory 获取哨兵模式下默认连接池的Redis客户端 RedisClient,可在 3.11 查看。

它的带参数的构造方法,用于初始化哨兵模式下默认连接池的Redis客户端【指定Redis数据库索引】。

方法 newCache 用于创建一个 RedisFleaCache 的实例对象,它里面包含了 读、写、删除 和 清空 缓存的基本操作,每一类 Redis 缓存数据都对应了一个 RedisFleaCache 的实例对象。

public class RedisSentinelFleaCacheManager extends AbstractFleaCacheManager {private RedisClient redisClient; // Redis客户端/*** 默认构造方法,初始化哨兵模式下默认连接池的Redis客户端** @since 2.0.0*/public RedisSentinelFleaCacheManager() {this(0);}/*** 初始化哨兵模式下默认连接池的Redis客户端,指定Redis数据库索引** @since 2.0.0*/public RedisSentinelFleaCacheManager(int database) {if (!RedisSentinelConfig.getConfig().isSwitchOpen()) return;// 初始化默认连接池RedisSentinelPool.getInstance().initialize(database);// 获取哨兵模式下默认连接池的Redis客户端redisClient = RedisClientFactory.getInstance(CacheModeEnum.SENTINEL);}@Overrideprotected AbstractFleaCache newCache(String name, int expiry) {int nullCacheExpiry = RedisSentinelConfig.getConfig().getNullCacheExpiry();if (RedisSentinelConfig.getConfig().isSwitchOpen())return new RedisFleaCache(name, expiry, nullCacheExpiry, CacheModeEnum.SENTINEL, redisClient);elsereturn new EmptyFleaCache(name, expiry, nullCacheExpiry);}
}

3.11 定义Redis客户端工厂类

RedisClientFactory ,有四种方式获取 Redis 客户端:

  • 一是获取分片模式下默认连接池的 Redis 客户端,应用在单个缓存接入场景;
  • 二是获取指定模式下默认连接池的 Redis 客户端,应用在单个缓存接入场景【3.10 采用】;
  • 三是获取分片模式下指定连接池的 Redis 客户端,应用在整合缓存接入场景;
  • 四是获取指定模式下指定连接池的 Redis 客户端,应用在整合缓存接入场景。

/*** Redis客户端工厂,用于获取Redis客户端。** @author huazie* @version 1.1.0* @since 1.0.0*/
public class RedisClientFactory {private static final ConcurrentMap<String, RedisClient> redisClients = new ConcurrentHashMap<>();private static final Object redisClientLock = new Object();private RedisClientFactory() {}/*** 获取分片模式下默认连接池的Redis客户端** @return 分片模式的Redis客户端* @since 1.0.0*/public static RedisClient getInstance() {return getInstance(CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME);}/*** 获取指定模式下默认连接池的Redis客户端** @param mode 缓存模式* @return 指定模式的Redis客户端* @since 1.1.0*/public static RedisClient getInstance(CacheModeEnum mode) {return getInstance(CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME, mode);}/*** 获取分片模式下指定连接池的Redis客户端** @param poolName 连接池名* @return 分片模式的Redis客户端* @since 1.0.0*/public static RedisClient getInstance(String poolName) {return getInstance(poolName, CacheModeEnum.SHARDED);}/*** 获取指定模式下指定连接池的Redis客户端** @param poolName 连接池名* @param mode     缓存模式* @return 指定模式的Redis客户端* @since 1.1.0*/public static RedisClient getInstance(String poolName, CacheModeEnum mode) {String key = StringUtils.strCat(poolName, CommonConstants.SymbolConstants.UNDERLINE, StringUtils.valueOf(mode.getMode()));if (!redisClients.containsKey(key)) {synchronized (redisClientLock) {if (!redisClients.containsKey(key)) {RedisClientStrategyContext context = new RedisClientStrategyContext(poolName);redisClients.putIfAbsent(key, FleaStrategyFacade.invoke(mode.name(), context));}}}return redisClients.get(key);}
}

在上面 的 getInstance(String poolName, CacheModeEnum mode) 方法中,使用了 RedisClientStrategyContext ,用于定义 Redis 客户端策略上下文。根据不同的缓存模式,就可以找到对应的 Redis 客户端策略。

3.12 定义Redis客户端策略上下文

RedisClientStrategyContext 可参考笔者的这篇博文 Redis分片模式接入,不再赘述。

3.13 定义哨兵模式Redis客户端策略

RedisSentinelClientStrategy 用于新建一个 Flea Redis 哨兵客户端。

/*** 哨兵模式Redis客户端 策略** @author huazie* @version 2.0.0* @since 2.0.0*/
public class RedisSentinelClientStrategy implements IFleaStrategy<RedisClient, String> {@Overridepublic RedisClient execute(String poolName) throws FleaStrategyException {RedisClient originRedisClient;// 新建一个Flea Redis哨兵客户端类实例if (CommonConstants.FleaPoolConstants.DEFAULT_POOL_NAME.equals(poolName)) {originRedisClient = new FleaRedisSentinelClient.Builder().build();} else {originRedisClient = new FleaRedisSentinelClient.Builder(poolName).build();}return originRedisClient;}
}

好了,到这里我们可以来测试 Redis 哨兵模式。

3.14 Redis集群模式接入自测

单元测试类 FleaCacheTest

首先,这里需要按照 Redis哨兵配置文件 中的地址部署相应的 Redis哨兵服务Redis主从服务,后续有机会我再出一篇简单的Redis主从 + 哨兵的搭建博文。

    @Testpublic void testRedisSentinelFleaCache() {try {// 哨兵模式下Flea缓存管理类,复用原有获取方式
//            AbstractFleaCacheManager manager = FleaCacheManagerFactory.getFleaCacheManager(CacheEnum.RedisSentinel.getName());// 哨兵模式下Flea缓存管理类,指定数据库索引AbstractFleaCacheManager manager = FleaCacheManagerFactory.getFleaCacheManager(0);AbstractFleaCache cache = manager.getCache("fleajerseyresource");LOGGER.debug("Cache={}", cache);//#### 1.  简单字符串cache.put("author", "huazie");cache.put("other", null);
//            cache.get("author");
//            cache.get("other");
//            cache.delete("author");
//            cache.delete("other");
//            cache.clear();cache.getCacheKey();LOGGER.debug(cache.getCacheName() + ">>>" + cache.getCacheDesc());} catch (Exception e) {LOGGER.error("Exception:", e);}}

4. 进阶接入

4.1 定义抽象Spring缓存

AbstractSpringCache 可参考笔者的这篇博文 Memcached接入,不再赘述。

4.2 定义Redis Spring缓存类

RedisSpringCache 可参考笔者的这篇博文 Redis分片模式接入,不再赘述。

4.3 定义抽象Spring缓存管理类

AbstractSpringCacheManager 可参考笔者的这篇博文 Memcached接入,不再赘述。

4.4 定义Redis哨兵模式Spring缓存管理类

RedisSentinelSpringCacheManager 继承抽象 Spring 缓存管理类 AbstractSpringCacheManager,用于接入Spring框架管理Redis缓存; 基本实现同 RedisSentinelFleaCacheManager,唯一不同在于 newCache 的实现。

它的默认构造方法,用于初始化哨兵模式下默认连接池的Redis客户端【默认Redis数据库索引为0】, 这里需要先初始化Redis哨兵连接池,默认连接池名为【default】; 然后通过 RedisClientFactory 获取哨兵模式下默认连接池的Redis客户端 RedisClient,可在 3.11 查看。

它的带参数的构造方法,用于初始化哨兵模式下默认连接池的Redis客户端【指定Redis数据库索引】。

方法【newCache】用于创建一个Redis Spring缓存, 而它内部是由Redis Flea缓存实现具体的 读、写、删除 和 清空 缓存的基本操作。

public class RedisSentinelSpringCacheManager extends AbstractSpringCacheManager {private RedisClient redisClient; // Redis客户端/*** 默认构造方法,初始化哨兵模式下默认连接池的Redis客户端** @since 2.0.0*/public RedisSentinelSpringCacheManager() {this(0);}/*** 初始化哨兵模式下默认连接池的Redis客户端,指定Redis数据库索引** @since 2.0.0*/public RedisSentinelSpringCacheManager(int database) {if (!RedisSentinelConfig.getConfig().isSwitchOpen()) return;// 初始化默认连接池RedisSentinelPool.getInstance().initialize(database);// 获取哨兵模式下默认连接池的Redis客户端redisClient = RedisClientFactory.getInstance(CacheModeEnum.SENTINEL);}@Overrideprotected AbstractSpringCache newCache(String name, int expiry) {int nullCacheExpiry = RedisSentinelConfig.getConfig().getNullCacheExpiry();if (RedisSentinelConfig.getConfig().isSwitchOpen())return new RedisSpringCache(name, expiry, nullCacheExpiry, CacheModeEnum.SENTINEL, redisClient);elsereturn new RedisSpringCache(name, new EmptyFleaCache(name, expiry, nullCacheExpiry));}}

4.5 spring 配置

如下用于配置缓存管理 redisSentinelSpringCacheManager,其中 configMap 为缓存时间(key缓存对象名称 value缓存过期时间)

    <bean id="redisSentinelSpringCacheManager" class="com.huazie.fleaframework.cache.redis.manager.RedisSentinelSpringCacheManager"><!-- 使用带参数的构造函数实例化,指定Redis数据库索引 --><!--<constructor-arg index="0" value="0"/>--><property name="configMap"><map><entry key="fleajerseyi18nerrormapping" value="86400"/><entry key="fleajerseyresservice" value="86400"/><entry key="fleajerseyresclient" value="86400"/><entry key="fleajerseyresource" value="86400"/></map></property></bean><!-- 开启缓存 --><cache:annotation-driven cache-manager="redisSentinelSpringCacheManager" proxy-target-class="true"/>

4.6 缓存自测

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:applicationContext.xml"})
public class SpringCacheTest {private static final FleaLogger LOGGER = FleaLoggerProxy.getProxyInstance(SpringCacheTest.class);@Autowired@Qualifier("redisSentinelSpringCacheManager")private AbstractSpringCacheManager redisSentinelSpringCacheManager;@Testpublic void testRedisSentinelSpringCache() {try {// 哨兵模式下Spring缓存管理类AbstractSpringCache cache = redisSentinelSpringCacheManager.getCache("fleajerseyresource");LOGGER.debug("Cache = {}", cache);//#### 1.  简单字符串cache.put("menu1", "huazie");cache.put("menu2", null);
//            cache.get("menu1");
//            cache.get("menu2");
//            cache.getCacheKey();
//            cache.delete("menu1");
//            cache.delete("menu2");
//            cache.clear();cache.getCacheKey();AbstractFleaCache fleaCache = (AbstractFleaCache) cache.getNativeCache();LOGGER.debug(fleaCache.getCacheName() + ">>>" + fleaCache.getCacheDesc());} catch (Exception e) {LOGGER.error("Exception:", e);}}
}

结语

到这一步,Redis 哨兵模式单独接入的内容终于搞定了,有关整合接入Redis哨兵模式的,请查看笔者的《整合Memcached和Redis接入》。

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

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

相关文章

OpenAI for Countries:全球AI基础设施的“技术基建革命”

2025年5月7日&#xff0c;OpenAI宣布启动“OpenAI for Countries”计划&#xff0c;目标是为全球各国构建本土化的AI基础设施&#xff0c;提供定制化服务。这一计划被视为其“星际之门”项目的全球化延伸&#xff0c;以技术合作为核心&#xff0c;覆盖数据中心建设、模型适配与…

Linux精确列出非法 UTF-8 字符的路径或文件名

Docker构建的时候报错:failed to solve: Internal: rpc error: code = Internal desc = grpc: error while marshaling: string field contains invalid UTF-8 1、创建一个test.sh文件 find . -print0 | while IFS= read -r -d file;

FFmpeg在Android开发中的核心价值是什么?

FFmpeg 在 Android 开发中的核心价值主要体现在其强大的多媒体处理能力和灵活性上&#xff0c;尤其在音视频编解码、流媒体处理及跨平台兼容性方面具有不可替代的作用。以下是具体分析&#xff1a; --- 1. 强大的音视频编解码能力 - 支持广泛格式&#xff1a;FFmpeg 支持几乎所…

自我奖励语言模型:突破人类反馈瓶颈

核心思想 自我奖励语言模型提出了一种全新的语言模型对齐范式。传统方法如RLHF或DPO依赖人类反馈数据训练固定的奖励模型&#xff0c;这使模型的能力受限于人类标注数据的质量和数量。论文作者认为&#xff0c;要实现超人类能力的AI代理&#xff0c;未来的模型需要突破人类反馈…

5. 动画/过渡模块 - 交互式仪表盘

5. 动画/过渡模块 - 交互式仪表盘 案例&#xff1a;数据分析仪表盘 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title></head><style type"text/css">.dashboard {font-family: Arial…

【前端三剑客】Ajax技术实现前端开发

目录 一、原生AJAX 1.1AJAX 简介 1.2XML 简介 1.3AJAX 的特点 1.3.1AJAX 的优点 1.3.2AJAX 的缺点 1.4AJAX 的使用 1.4.1核心对象 1.4.2使用步骤 1.4.3解决IE 缓存问题 1.4.4AJAX 请求状态 二、jQuery 中的AJAX 2.1 get 请求 2.2 post 请求 三、跨域 3.1同源策略…

SQL 索引优化指南:原理、知识点与实践案例

SQL 索引优化指南&#xff1a;原理、知识点与实践案例 索引的基本原理 索引是数据库中用于加速数据检索的数据结构&#xff0c;类似于书籍的目录。它通过创建额外的数据结构来存储部分数据&#xff0c;使得查询可以快速定位到所需数据而不必扫描整个表。 索引的工作原理 B-…

typedef unsigned short uint16_t; typedef unsigned int uint32_t;

你提到的这两行是 C/C 中的类型别名定义&#xff1a; typedef unsigned short uint16_t; typedef unsigned int uint32_t;它们的目的是让代码更具可读性和可移植性&#xff0c;尤其在处理精确位数的整数时非常有用。 ✅ 含义解释 typedef unsigned short uint16_t;…

Hapi.js知识框架

一、Hapi.js 基础 1. 核心概念 企业级Node.js框架&#xff1a;由Walmart团队创建&#xff0c;现由社区维护 配置驱动&#xff1a;强调声明式配置而非中间件 插件架构&#xff1a;高度模块化设计 安全优先&#xff1a;内置安全最佳实践 丰富的生态系统&#xff1a;官方维护…

【PostgreSQL数据分析实战:从数据清洗到可视化全流程】金融风控分析案例-10.3 风险指标可视化监控

&#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 &#x1f449; 点击关注不迷路 文章大纲 PostgreSQL金融风控分析之风险指标可视化监控实战一、引言二、案例背景三、数据准备&#xff08;一&#xff09;数据来源与字段说明&#xff08;二&#xff09;数据清洗 四、…

屏幕与触摸调试

本章配套视频介绍: 《28-屏幕与触摸设置》 【鲁班猫】28-屏幕与触摸设置_哔哩哔哩_bilibili LubanCat-RK3588系列板卡都支持mipi屏以及hdmi显示屏的显示。 19.1. 旋转触摸屏 参考文章 触摸校准 参考文章 旋转触摸方向 配置触摸旋转方向 1 2 # 1.查看触摸输入设备 xinput…

AbstractQueuedSynchronizer之AQS

一、前置知识 公平锁和非公平锁&#xff1a; 公平锁&#xff1a;锁被释放以后&#xff0c;先申请的线程先得到锁。性能较差一些&#xff0c;因为公平锁为了保证时间上的绝对顺序&#xff0c;上下文切换更频繁 非公平锁&#xff1a;锁被释放以后&#xff0c;后申…

内存泄漏系列专题分析之十一:高通相机CamX ION/dmabuf内存管理机制Camx ImageBuffer原理

【关注我,后续持续新增专题博文,谢谢!!!】 上一篇我们讲了:内存泄漏系列专题分析之八:高通相机CamX内存泄漏&内存占用分析--通用ION(dmabuf)内存拆解 这一篇我们开始讲: 内存泄漏系列专题分析之十一:高通相机CamX ION/dmabuf内存管理机制Camx ImageBuf…

《类和对象(下)》

引言&#xff1a; 书接上回&#xff0c;如果说类和对象&#xff08;上&#xff09;是入门阶段&#xff0c;类和对象&#xff08;中&#xff09;是中间阶段&#xff0c;那么这次的类和对象&#xff08;下&#xff09;就可以当做类和对象的补充及收尾。 一&#xff1a;再探构造…

Java MVC

在软件开发中&#xff0c;MVC&#xff08;Model-View-Controller&#xff09;是一种常用的设计模式&#xff0c;它将应用程序分为三个核心部分&#xff1a;模型&#xff08;Model&#xff09;、视图&#xff08;View&#xff09;和控制器&#xff08;Controller&#xff09;。这…

嵌入式学习笔记 - 关于单片机的位数

通常我们经常说一个单片机是8位的&#xff0c;16位的&#xff0c;32位的&#xff0c;那么怎么判断一款单片机的位数是多少位呢&#xff0c;判断的依据是什么呢&#xff0c; 一 单片机的位数 单片机的位数是指单片机数据总线的宽度&#xff0c;也就是一次能处理的数据的位数&a…

推荐几个常用免费的文本转语音工具

推荐几个常用免费的文本转语音工具 在数字内容创作的时代&#xff0c;文本转语音(TTS)技术已经成为内容创作者的得力助手。无论是制作视频配音、有声读物、还是为网站增加语音功能&#xff0c;这些工具都能大幅提高创作效率。今天&#xff0c;我将为大家推荐几款优质的免费文本…

Microsoft Azure DevOps针对Angular项目创建build版本的yaml

Azure DevOps针对Angular项目创建build版本的yaml&#xff0c;并通过变量控制相应job的执行与否。 注意事项&#xff1a;代码前面的空格是通过Tab控制的而不是通过Space控制的。 yaml文件中包含一下内容&#xff1a; 1. 自动触发build 通过指定code branch使提交到此代码库的…

Python Day23 学习

继续SHAP图绘制的学习 1. SHAP特征重要性条形图 特征重要性条形图&#xff08;Feature Importance Bar Plot&#xff09;是 SHAP 提供的一种全局解释工具&#xff0c;用于展示模型中各个特征对预测结果的重要性。以下是详细解释&#xff1a; 图的含义 - 横轴&#xff1a;表示…

.NET 8 + Angular WebSocket 高并发性能优化

.NET 8 Angular WebSocket 高并发性能优化。 .NET 8 WebSocket 高并发性能优化 WebSocket 是一种全双工通信协议&#xff0c;允许客户端和服务端之间保持持久连接。在高并发场景下&#xff0c;优化 WebSocket 的性能至关重要。以下是针对 .NET 8 中 WebSocket 高并发性能优化…