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.pswp.cn/web/79662.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/79662.shtml
英文地址,請注明出處:http://en.pswp.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 高并發性能優化…